Grails Mongo Low Level API - mongodb

What would be the equivalent of this line in groovy code when using the Mongo low level API?
db.countrycodes.findOne({"Country":"Antarctica"})
This line successfully finds the appropriate record for me in the Mongo shell but I tried many variations of it in my controller method and I keep getting NULL. Heres is my current attempt which is failing:
MongoClient mongoClient = new MongoClient("localhost", 27017)
DB db = mongoClient.getDB("twcdb");
DBCollection coll = db.getCollection('countrycodes')
println coll.find("Country":"Antarctica")
I know my collection and db is non NULL because when I do find() I do get a valid cursor back through which I can print the first record in collection. Here is the record I am trying to find:
{
"_id" : ObjectId("539848b2119918654e7e90b1"),
"Country" : "Antarctica",
"Alpha2" : "AQ",
"Aplha3" : "ATA",
"Numeric" : "10",
"FIPS" : "AY",
"IGA" : ""
}

Try this:
def cursor = coll.find()
def obj = cursor.next()
while (obj.Country != 'Antarctica') {
obj = cursor.next()
}
It is inefficient, you will have to traverse the whole collection everytime to find a record, but it will end up with 'obj' being the record you need.

Try below code and see if it works.
BasicDBObject query = new BasicDBObject("Country", "Antartica");
def cursor = coll.find(query)
try {
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
} finally {
cursor.close();
}
For more info look here: http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-java-driver/

Related

How to retrieve values of nested objects in a Mongo DB document using java

I have a document like below:
"application" : "test",
"QA1" : {
"url" : "https://google.co.in",
"db" : {
"userName" : "user",
"password" : "pswd"
}
}
I want to retrieve the value "https://google.co.in" by calling the key "url".
While using the below shell command, I am able to retrieve the value as expected.
db.getCollection('Application_Data').findOne({"application":"test"}).QA1.url
But when I convert it to java code, it is throwing me null pointer exception:
cursor = collection.find(Filters.eq("application","test")).iterator();
while (cursor.hasNext()) {
value=cursor.next().get("QA1.url").toString();
break;
}
I also tried with projection like below to get the required values:
cursor = collection.find(Filters.and(Filters.eq("application","test"))).projection(Projections.fields(Projections.include("QA1.url"),Projections.excludeId())).iterator();
while (cursor.hasNext()) {
System.out.println(cursor.next().get("QA1").toString());
}
This is giving me the output as below:
Document{{url=https://google.co.in}}
It is still not giving me the exact value. Appreciate your help on this.
Mongodb Documents are nested. So say, in your example, when you do cursor.next().get("QA1"), you get the Document under "QA1" property.
So the way to achieve what you want is
cursor.next().get("QA1").get("url"). That, with proper error handling (think exceptions).
A better way to do what you want is to use a mapper like spring-data-mongodb that would map the JSON response of mongodb into a java object for you automatically.
You need to use the Document class's getEmbedded method to extract the nested field's value.
while (cursor.hasNext()) {
Document doc = cursor.next();
System.out.println(doc.toJson());
String urlValue = doc.getEmbedded(Arrays.asList("QA1","url"), String.class);
System.out.println(urlValue); // output below
}
The result is as expected - a string: https://google.co.in

mongo group with match query does not work with java

I have below query working in robo 3T console.
db.metrics.aggregate([
{'$match':{'status':'SUCCESS'}},
{'$group':{ _id:'$bapiName',count:{$sum:1}}}
])
But when I execute it with java,
MongoCollection collection =db.getCollection();
List<Bson> pipeLine = new ArrayList<Bson>();
pipeLine.add(Document.parse("{'$match':{'status':'SUCCESS'}}"));
pipeLine.add(Document.parse("{'$group' : {_id: {bapiName:'$bapiName',status:'$status'}, count:{$sum:1}}}"));
Iterator iterator = collection.aggregate(query.getPipeline()).iterator();
while( iterator.hasNext()) {
Object object = iterator.next();
resultList.add((Document)object);
System.out.println(" class "+object.getClass()+" data "+object);
}
I am not getting the results. Iterator is empty. Any changes need to be made in java to get it working?

Mongo DB : Implementing $not query

I am trying to implement following query from java code:
{ "Post Text" : { "$not" : /.*golf.*/i}}
my java code:
BasicDBObject not = new BasicDBObject();
not.append("$not", "/.*golf.*/i");
BasicDBObject query = new BasicDBObject();
query.put("Post Text", not);
When I am running above query, getting this log:
Cursor id=0, ns=journaldev.Rotunda, query={ "Post Text" : { "$not" : "/.golf./i" }}, numIterated=0, readPreference=primary
extra quotes around the regular expression are creating problem. Can someone help me in fixing this?
Using 3.x, you can use the Filters utility class to create various queries for you. In your case, you need the following construct:
Bson myFilter = Filters.not(
Filters.eq("Post Text",
Pattern.compile(".*golf.*", Pattern.CASE_INSENSITIVE)));
Using the 3.x driver to execute such a query is along the lines of:
MongoClient mongoClient = new MongoClient();
MongoCollection<Document> coll = mongoClient.getDatabase("test").getCollection("mycoll");
coll.find(myFilter); // do something with the FindIterable returned here
You can try something like this
Pattern textRegex = Pattern.compile(".*golf.*", Pattern.CASE_INSENSITIVE);
BasicDBObject not = new BasicDBObject("$not", textRegex);
BasicDBObject query = new BasicDBObject("Post Text", not);
When you pass a pattern, mongo driver automatically takes care of making it a regex. If you debug and see the code it will run with "$regex".
Hope this solves the problem

MongoDB: $in with an ObjectId array

Just a quick question about something I've just experienced and I'm still thinking about why:
mongos> db.tickets.count({ "idReferenceList" : { "$in" : [ { "$oid" : "53f1f09f2cdcc8f339e5efa2"} , { "$oid" : "5409ae2e2cdc31c5aa0ce0a5"}]}});
0
mongos> db.tickets.count({ "idReferenceList" : { "$in" : [ ObjectId("53f1f09f2cdcc8f339e5efa2") , ObjectId("5409ae2e2cdc31c5aa0ce0a5")]}});
2
I thought that both $oid and ObjectId spelling formats where exactly the same for MongoDB. Does anyone know why with the first query return 0 results and with the second one is returning 2 (the right answer)?
Furthermore, I'm using Morphia framework which uses MongoDB Java driver to interact with MongoDB. I've realised that there exists a problem by searching with $in operator in ObjectIds arrays over fields that are not _id by executing this lines of code:
List< ObjectId > fParams = new ArrayList< ObjectId >();
fParams.add(...);
Query<Ticket> query = genericDAO.createQuery();
query.field("idReferenceList").in(fParams);
result = genericDAO.find(query).asList();
Thank you very much in advance.
Regards,
Luis Cappa
Both these formats are valid representations of an object id in MongoDB, according to the documentation,
http://docs.mongodb.org/manual/reference/mongodb-extended-json/
and they represented differently in the two modes,
Strict Mode mongo Shell Mode
----------- ----------------
{ "$oid": "<id>" } ObjectId( "<id>" )
So, to query fields which contain objectid, from the shell/console mode, you need to use ObjectId("<id>").
Which is the syntax to be followed in the mongo shell mode.
Hence the query:
db.tickets.count({ "idReferenceList" : { "$in" : [ ObjectId("53f1f09f2cdcc8f339e5efa2") , ObjectId("5409ae2e2cdc31c5aa0ce0a5")]}});
would return you row count.
Now to do it via the Java API,
You need to do it as below:
String[] ids = {"53f1f09f2cdcc8f339e5efa2","5409ae2e2cdc31c5aa0ce0a5"};
ObjectId[] objarray = new ObjectId[ids.length];
for(int i=0;i<ids.length;i++)
{
objarray[i] = new ObjectId(ids[i]);
}
BasicDBObject inQuery = new BasicDBObject("$in", objarray);
BasicDBObject query = new BasicDBObject("idReferenceList", inQuery);
DBCursor cursor = db.collection.find(query);
while(cursor.hasNext())
{
DBObject doc = cursor.next();
// process the doc.
}
I faced the same issue.
I resolved like this way.
db.collection('post').find({ 'postIds': { $elemMatch: { $in:
deletedPosts.map(_post => {ObjectId(_post._id)}) } } })

Remove an array entry in an object using spring data mongodb

I recently spent some time trying to use the $pull operator through Spring's Data MongoOperations interface, so I thought it would be nice to share my findings in case anyone bumps into a similar problem.
So here it goes...
I have 2 java POJOs like so :
#Document
public class OutterObject{
private String id;
private String name;
private List<InnerDocument> innerDocs;
//SETTERS - GETTERS Ommited
public class InnerDocument{
private String id;
private String name;
//SETTERS - GETTERS Ommited
This is stored in a Mongo collection like so :
"_id" : "doc2",
"_class" : "OutterObject",
"name" : "doc2",
"innerDocs" : [{
"_id" : "innerDoc21",
"name" : "innerDoc21"
}, {
"_id" : "innerDoc22",
"name" : "innerDoc22"
}]
I'm trying to use the $pull operator in order to remove all objects inside the innerDoc collection having a name value = "innerDoc22".
I know how to accomplish this using the mongo driver like so :
List<String> ids =
Arrays.asList("innerDoc22");
BasicDBObject find = new BasicDBObject();
match.put("innerDocs.name",
BasicDBObjectBuilder.start("$in", ids).get());
BasicDBObject update = new BasicDBObject();
update.put(
"$pull",
BasicDBObjectBuilder.start("innerDocs",
BasicDBObjectBuilder.start("name", "innerDoc22").get()).get());
DBCollection col= mongoOperations.getDb().getCollection("outterObject");
col.update(find , update);
I'm trying to accomplish the same thing using Spring's MongoOperations Interface.
Here is my code using the MongoOperations interface :
List<String> ids = Arrays.asList("innerDoc22");
Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));
WriteResult wc = mongoOperations.upsert(
removeQuery,
new Update().pull("innerDocs.name", "innerDoc22"),
OutterObject.class);
System.out.println(wc.getLastError());
I'm not getting any errors when calling getLastError() the update is simply not done in the database.
I know a similar question has already been asked here but the answer that was given does not use the MongoOperations interface.
After searching a bit and looking at the source code I realized that I needed to pass an InnerDocument object as a second parameter to the pull method so that the spring classes would be able to do the mapping correctly.
As it turns out I can navigate objects while selecting objects (I'm using "innerDocs.name" in the removeQuery) but I cannot (or havent found a way) do the same when updating a document.
Below is how I implemented the query using MongoOperations :
List<String> ids = Arrays.asList("innerDoc22", "innerDoc21");
Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));
WriteResult wc =
mongoOperations.upsert(removeQuery,
new Update().pull("innerDocs",
new InnerDocument("innerDoc22", null)),
OutterObject.class);
System.out.println(wc.getLastError());
You can also use the BasicDBObject instead of the InnerDocument I found this out by accident. By printing out the update object, you can see the actual mongo shell query json, which is super helpful for debugging.
:
Update updateObj = new Update()
.pull("innerDocs", new BasicDBObject("innerDocs.name","innerDoc22"));
System.out.println("UPDATE OBJ: " + updateObj.toString());
results in:
UPDATE OBJ: { "$pull" : { "innerDocs" : { "innerDocs.name" : "innerDoc22"}}}
I tried the solution given by med116 and I had to modify it to work :
Update updateObj = new Update().pull("innerDocs", new BasicDBObject("name","innerDoc22"));
Because otherwise there was no matching object in my array.
in spring data mongo,just like this:
//remove array's one elem
UpdateResult wc = mongoTemplate.upsert(removeQuery,new Update().pull("tags",Query.query(Criteria.where("tag").is("java"))),TestPull.class);
//remove array's multi-elem
UpdateResult wc1 = mongoTemplate.upsert(removeQuery,new Update().pull("tags",Query.query(Criteria.where("tag").in(Arrays.asList("mongo", "netty")))),TestPull.class);
If you simply want to remove an element from array which does not have any other property like name then write the query you wish and
Update update = new Update();
update.pull("Yourarrayname","valueyouwishtodelete");
mongoTemplate.upsert(query,update,"collectionname");
That's my solution - thanks to #ufasoli:
public Mono<ProjectChild> DeleteCritTemplChild(String id, String idch) {
Query query = new Query();
query.addCriteria(Criteria
.where("_id")
.is(id)
.and("tasks._id")
.is(idch)
);
Update update = new Update();
update.set("tasks.$", null);
return template
// findAndModify:
// Find/modify/get the "new object" from a single operation.
.findAndModify(
query, update,
new FindAndModifyOptions().returnNew(true), ProjectChild.class
);
}
This works for me!
UpdateResult updateResult = mongoTemplate.updateMulti(new Query(where("id").is(activity.getId())), new Update().pull("comments", new Query(where("id").is(commentId))), Activity.class);
It will generate:
Calling update using query: { "_id" : { "$oid" : "61f900e7c7b79442eb3855ea"}} and update: { "$pull" : { "comments" : { "_id" : "61fac32e3f9ab5646e016bc8"}}} in collection: activity