I have the following json structure. I am trying to retreive run the following mongo query in java where hData._id is not null.
MongoDb Query: db.Collection.find({},{"hData._id":1, "hData.createdBy":1} )
{
"_id" : ObjectId("55567e594e3256a23565ce58"),
"hData" : {
"isDeleted" : false,
"canDelete" : false,
"canUpdate" : false,
"createdBy" : “xyz”,
"createdDate" : "2015-05-15T15:05:30",
"_id" : "7"
},
"changeDate" : "2015-02-19T16:02:12",
}
The code i have written in java to fetch the hData._id is
MongoCursor<Document> cur = col.find(new BasicDBObject("hData._id", new BasicDBObject("$ne",null)))).iterator();
try{
while(cur.hasNext()){
System.out.println(cur.next().getObjectId("hData._id"));
i++;
}
}finally {
cur.close();
}
However, hData._id is returned as null. Could you help me with this ?
You can't get nested properties using dot notation, e.g. x.y.
So in your example you need to get hData first, then call get on the _id. Like this:
MongoCursor<Document> cur = col.find(new BasicDBObject("hData._id", new BasicDBObject("$ne",null))).iterator();
while(cur.hasNext()){
System.out.println(cur.next().get("hData", Document.class).getString("_id"));
}
Also note that in your example hData._id is shown as a String and not as an ObjectId, hence in my example I've used getString().
EDIT
Since it sounds like you may have mixed types for hData._id here's a more robust example with type checking and some extra debug output to illustrate:
MongoCursor<Document> cur = col.find(new BasicDBObject("hData._id", new BasicDBObject("$ne",null))).iterator();
while(cur.hasNext()){
Document doc = cur.next();
System.out.println("Document _id" + doc.get("_id"));
Document hdata = doc.get("hData", Document.class);
Object id = hdata.get("_id");
System.out.println("hData._id " + id);
// check type if you need to
if (id instanceof String) {
System.out.println("hData._id is String: " + id);
} else if (id instanceof ObjectId) {
System.out.println("hData._id is ObjectId: " + id);
} else {
System.out.println("hData._id is of type " + id.getClass().getName());
}
}
You can use Filters and Projections helper methods.
try (MongoCursor<Document> cur = coll.find(Filters.ne("hData._id", null)).projection(Projections.include("hData._id", "hData.createdBy")).iterator()) {
while(cur.hasNext()){
Document doc = cur.next();
Document hData = doc.get("hData", Document.class);
String id = hData.getString("_id");
String createdBy = hData.getString("createdBy");
}
}
Related
I understand that there are many questions which as for the same and they are answered well. The problem is all those questions use MongoDBObject, MongoDBList to retrieve arrays. My problem is I am using http://api.mongodb.org/java/3.0/index.html?overview-summary.html api and I am having hard time retrieving array and adding elements to it. I have to use MongoCollection, MongoDatabase and MongoClient. I am trying to solve an assignment from mongodb course. The problem statement is to find an array and update it in mongod.
Here is what I have tried
Document post = null; Bson filter = new Document("permalink",
permalink); Bson projection = new Document("comments", true);
List<Document> comments = postsCollection.find(filter)
.projection(projection).into(new ArrayList<Document>());
System.out.println(comments);
post = postsCollection.find(Filters.eq("permalink",
permalink)).first();
Document newComment = new Document();
newComment.append("author", name); newComment.append("body", body);
if (email != null && (!email.equals(""))) {
newComment.append("email", email); }
comments.add(newComment);
Bson filter2 = new Document("_id", post.get("_id"));
System.out.println(comments); post =
postsCollection.find(filter).first();
postsCollection.updateOne(filter2, new Document("$unset",new
Document("comments",true))); postsCollection.updateOne(filter2, new
Document("$set", new Document( "comments", comments)));
This does not create a new comment. Instead, it creates another comments array in comments array itself. THe array should be updated in student
Here is the json data
{
"_id" : ObjectId("55d965eee60dd20c14e8573e"),
"title" : "test title",
"author" : "prasad",
"body" : "test body",
"permalink" : "test_title",
"tags" : [
"test",
"teat"
],
"date" : ISODate("2015-08-23T06:19:26.826Z"),
"comments" : [
{
"_id" : ObjectId("55d965eee60dd20c14e8573e"),
"comments" : [
{
"_id" : ObjectId("55d965eee60dd20c14e8573e"),
"comments" : []
},
{
"author" : "commented",
"body" : "something in comment",
"email" : "some#thing.com"
}
]
},
{
"author" : "commented",
"body" : "something in comment",
"email" : "some#thing.com"
}
]
}
To avoid unchecked casts and linter warnings, along with writing your own loop, use the libary's get(final Object key, final Class<T> clazz) method:
List<Document> comments = posts.get("comments", docClazz)
where docClazz is something that you create once:
final static Class<? extends List> docClazz = new ArrayList<Document>().getClass();
You need not write to this much code. Please check following code,
public void addPostComment(final String name, final String email, final String body,
final String permalink) {
Document post = findByPermalink(permalink);
List<Document> comments = null;
Document comment = new Document();
if(post != null){
comments = (List<Document>)post.get("comments");
comment.append("author",name).append("body", body);
if(email != null){
comment.append("email", email);
}
comments.add(comment);
postsCollection.updateOne(new Document("permalink",permalink),
new Document("$set",new Document("comments",comments)));
}
}
This is much simplified here!
version - mongo-java-driver-3.12.5.jar
comments = post.getList("comments", Document.class);
If you're forced to use older version of mongo driver and you can't use the method the MKP has mentioned, then you can copy the method itself.
Here it is as a Kotlin extension
import org.bson.Document
import java.lang.String.format
fun <T> Document.getList(key: String, clazz: Class<T>, defaultValue: List<T>): List<T> {
val list = this.get(key, List::class.java)
if (list == null) {
return defaultValue
}
list.forEach {
if (!clazz.isAssignableFrom(it!!::class.java)) {
throw ClassCastException(format("List element cannot be cast to %s", clazz.getName()))
}
}
return list as List<T>
}
I am using Java Driver for MongoDB to query database. I am getting syntax errors when trying to execute range query on a date field in aggregation. It works fine if I use it as part of find query only. Aggregation is the problem here. I used the following Java query code :
new BasicDBObject("requestDate", BasicDBObjectBuilder.start("$gte", fromDate).add("$lte", toDate).get());
requestDate is the field I want to query. I tried debugging the code and ran the generated query using command line and I still get syntax errors. Not sure whats wrong here.
Mongo Query generated by the code:
{ "requestDate" : { "$gte" : { "$date" : "2015-03-01T05:00:00.000Z"} , "$lte" : { "$date" : "2015-03-09T04:00:00.000Z"}}}
EDIT. Adding relevant Code:
BasicDBObject match = null;
if (organizationId != null) {
match = new BasicDBObject("$match", new BasicDBObject("organizationId", organizationId));
}
if (optionalParams != null) {
Date fromDate = (Date) optionalParams.get("fromDate");
Date toDate = (Date) optionalParams.get("toDate");
if (match == null) {
match = new BasicDBObject("requestDate", new BasicDBObject("$gte", fromDate).append("$lte", toDate));
} else {
match.append("requestDate", new BasicDBObject("$gte", fromDate).append("$lte", toDate));
}
}
DBObject project = new BasicDBObject("$project", MongoDBUtil.getProjectDateFields());
DBObject groupFields = new BasicDBObject("_id", MongoDBUtil.getGroupDateFields()).append("total", new BasicDBObject("$sum", 1));
DBObject group = new BasicDBObject("$group", groupFields);
DBObject sort = new BasicDBObject("$sort", new BasicDBObject("_id", 1));
List<DBObject> pipeline;
if (match != null) {
pipeline = Arrays.asList(match, project, group, sort);
} else {
pipeline = Arrays.asList(project, group, sort);
}
In brief, you broke your $match pipeline stage construction because like all pipeline directives that "key" is "mandatory. Your conditional building should not be checking is the existing state is null but rather "appending" to what you need to define at the top as a "empty" $match:
// BasicDBObject match = null; // wrong!
BasicDBObject match = new BasicDBObject("$match", new BasicDBObject()); // correct!
if (organizationId != null) {
match.append("organizationId", organizationId);
}
if (optionalParams != null) {
Date fromDate = (Date) optionalParams.get("fromDate");
Date toDate = (Date) optionalParams.get("toDate");
match.append("requestDate", new BasicDBObject("$gte", fromDate)
.append("$lte", toDate));
}
So then, without a value for organizationId you get a pipeline generated like so:
{ "$match": {
"requestDate" : {
"$gte" : { "$date" : "2015-03-01T05:00:00.000Z" },
"$lte" : { "$date" : "2015-03-09T04:00:00.000Z" }
}
}
Without that $match key this is not a valid pipeline stage and it will error on submission to the aggregation pipeline.
There is nothing wrong with the generated syntax and all, full explanation is in the manual under Extended JSON. The MongoShell uses "strict" mode as mentioned there so it requires it's own wrappers.
Following is my Java controller method code
public List<MyClass> getStudentList(String studentName){
studentName = ".*" + studentName + ".*";
/* BasicDBObject field = new BasicDBObject();
field.put("regNo", 1);
field.put("name", 1);
field.put("collName", 1);
field.put("deptName", 1); */
Query query = new Query(Criteria.where("name").regex(studentName, "i"));
return mongoTemplate.find(query,MyClass.class, COLLECTION_NAME);
}
My Db looks like this
"regNo" : "1234", "name" : "ABCD", "collName" : "UNIVERSITY COLLEGE", "deptName" : "B.E. Computer Science and Engineering", "result" : [ { "subjCode" : "CS2251", "grade" : "E", "result" : "PASS", "subjName" : "Design and Analysis of Algorithms" }]
I want to select only regNo, name, collName and deptName. How can I do this?
Add this statement to query:
query.fields().include("regNo").include("name").include("collName").include("deptName").exclude("_id");
APPEND
If your codes like:
public List<MyClass> getStudentList(String studentName){
studentName = ".*" + studentName + ".*";
/* BasicDBObject field = new BasicDBObject();
field.put("regNo", 1);
field.put("name", 1);
field.put("collName", 1);
field.put("deptName", 1); */
Query query = new Query(Criteria.where("name").regex(studentName, "i"));
query.fields().include("regNo").include("name").include("collName").include("deptName").exclude("_id");
return mongoTemplate.find(query,MyClass.class, COLLECTION_NAME);
}
It should be fine.
By the query string you provided as:
var q = {
Query : {
"name" : {
"$regex" : ".*valueSearched.*",
"$options" : "i"
}
},
Fields : {
"collName" : 1,
"results" : 0, // disallowed
"_id" : 0,
"de‚Äå‚ÄãptName" : 1,
"name" : 1,
"regNo" : 1
}
};
You actually perform something similar to
query.fields().include("collName").exclude("results").exclude("_id").include("de‚Äå‚ÄãptName").include("name").include("regNo");
instead.
Please check your code accordingly. Maybe you've called query.fields().exculude("results") somewhere; ELSE, it has a bug from some part. :)
The regulation for including and excluding fields are:
If you include some fields, then only return these fields and
"_id" will return implicitly;
only "_id" is allowed to exclude;
If you exclude some normal fields, other fields will returned and
can not include other fields;
See here,it is deprecated but help you to understand
public DBCursor find(DBObject query,
DBObject fields,
int numToSkip,
int batchSize,
int options)
http://api.mongodb.org/java/current/com/mongodb/DBCollection.html#find%28com.mongodb.DBObject,%20com.mongodb.DBObject,%20int,%20int%29
If you dont want any warning ,you may use DBCursor Object.
public DBCursor(DBCollection collection,
DBObject q,
DBObject k,
ReadPreference preference)
Initializes a new database cursor
Parameters:
collection - collection to use
q - query to perform
k - keys to return from the query
preference - the Read Preference for this query
I don't use java driver but it shouldn't be much difficult.
For this issue you have to use #JsonInclude(value=Include.NON_NULL) in your pojo class like this:
#JsonInclude(value=Include.NON_NULL)
String id;
I'm using the Apache Chemistry OpenCMIS java library. Given a QueryResult (e.g. I found a document or a bunch of documents by searching on metadata properties), is this a reasonable way to retrieve the Document object itself? Or is there a more efficient way?
ItemIterable<QueryResult> results = session.query("SELECT * FROM cmis:document WHERE cmis:name LIKE 'test%'", false);
for(QueryResult hit: results) {
Document document = (Document) session.getObject(session.createObjectId((String) hit.getPropertyValueById("cmis:objectId")));
}
Try the Session.queryObjects() method.
For me this works perfectly
String myType = "my:documentType";
// get the query name of cmis:objectId
ObjectType type = session.getTypeDefinition(myType);
PropertyDefinition<?> objectIdPropDef = type.getPropertyDefinitions().get(PropertyIds.OBJECT_ID);
String objectIdQueryName = objectIdPropDef.getQueryName();
String queryString = "SELECT " + objectIdQueryName + " FROM " + type.getQueryName();
// execute query
ItemIterable<QueryResult> results = session.query(queryString, false);
for (QueryResult qResult : results) {
String objectId = qResult.getPropertyValueByQueryName(objectIdQueryName);
Document doc = (Document) session.getObject(session.createObjectId(objectId));
}
Found here: https://chemistry.apache.org/java/examples/example-process-query-results.html
I would like to use mongodb.core.query.Criteria for following request:
db.accounts.find({ "personalSettings.nickName" : "testNickName"})
My scheme of document is:
{
"_id" : ObjectId("5354de90ad9b0f6c60bef7ba"),
"personalSettings" : {
"avatar" : "http://127.0.0.1:8080/assets/samples/avatar.png",
"nickName" : "testNickName"
},
"userName" : "testUser#testDomain.com"
}
I've tried to use this:
Query query = new Query(Criteria.where("personalSettings.nickName").is("testNickName"));
but i got:
java.lang.IllegalArgumentException: [Assertion failed] - this argument is required; it must not be null
personalSettings is a Map of < String,String >
Thanks
#Override
public Account getAccountByNickName(String nickname, String accountsCollection) {
Criteria criteria = Criteria.where("personalSettings.nickName").is(nickname);
DBCollection coll = mongoOperation.getCollection(accountsCollection);
DBCursor dbCursor = coll.find(Query.query(criteria).getQueryObject());
DBObject dbobj = dbCursor.next();
Account account = (new Gson()).fromJson(dbobj.toString(), Account.class);
return account;
}
For now - only one way :)
Because MongoDB doesn't support searching in map by elemMatch and doesn't support searching by ongoTemplate/MongoOperation