MongoDB Java Driver - Use exists projection in find query - java

I want to get all documents where the field download does not exists
find{ "download" : {$exists: false}}
For Java I found an Example:
BasicDBObject neQuery = new BasicDBObject();
neQuery.put("number", new BasicDBObject("$ne", 4));
DBCursor cursor = collection.find(neQuery);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
My Adaption is
BasicDBObject field = new BasicDBObject();
field.put("entities.media", 1);
field.put("download", new BasicDBObject("$exists",false));
System.out.println("Start Find");
DBCursor cursor = collection.find(query,field);
System.out.println("End Find Start Loop ALL 100k");
int i = 1;
while(cursor.hasNext())
The Exists Line is not working:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: com.mongodb.MongoException: Unsupported projection option: $exists
at com.mongodb.MongoException.parse(MongoException.java:82)
at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:314)
at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:295)
at com.mongodb.DBCursor._check(DBCursor.java:368)
at com.mongodb.DBCursor._hasNext(DBCursor.java:459)
at com.mongodb.DBCursor.hasNext(DBCursor.java:484)
at ImgToDisk.main(ImgToDisk.java:61)
... 5 more
It have no clue right now which the right adaption would be, since I got my query working in the shell and with UMongo, the transfer to java seems to be not so easy to see.

you use
collection.find(query,field);
the DBObject that is the 2nd parameter to the find method is used to indicate which attributes of the resulting documents you want to be returned. It is useful for reducing network load.
In your example, you try to put an $exists clause into the field DBObject. That won't work.
The 2nd parameter object can only have attribute values of 1(include this attribute) or 0(exclude).
Put it into the first DBObject called query instead.
Also see here and here

you can use DBCollection to do that with JAVA API
public List<BasicDBObject> Query(String collection, Map<String, String> query, String... excludes) {
BasicDBObject bquery = new BasicDBObject(query);
BasicDBObject bexcludes = new BasicDBObject(excludes.length);
for (String ex : excludes) {
bexcludes.append(ex, false);
}
return db.getCollection(collection, BasicDBObject.class).find(bquery).projection(bexcludes)
.into(new ArrayList<BasicDBObject>());
}
db is MongoDataBase

We need to specify two things.
First :
collection.find(query,field);
The above command is not from MongoDB Java driver.
That means we can run only in the mongo shell (or in the mongo Compass) and not in the java.
Second:
to limit the fields in java you can use projection() like the following code
find(queryFilter)
.projection(fields(include("title", "year"),exclude("_id")))
Complete Example:
Bson queryFilter = eq("cast", "Salma Hayek");
//or Document queryFilter = new Document("cast", "Salma Hayek");
Document result =
collection
.find(queryFilter)
//.limit(1) if you want to limit the result
.projection(fields(include("title", "year"),exclude("_id")))
//or .projection(fields(include("title", "year"), excludeId()))
//or .projection(new Document("title", 1).append("year", 1))
.iterator()
.tryNext();

Related

How to execute mongo query from spring's mongo template?

I am trying to execute queries like "db.post.find().pretty()" from executeCommand of mongoTemplete of spring framework. But I am unable to do it?Is there a way to execute queries like above directly from mongotempelate? Any help is appreciated.
Here is my code:
public CommandResult getMongoReportResult(){
CommandResult result=mongoTemplate.executeCommand("{$and:[{\"by\":\"tutorials point\"},{\"title\": \"MongoDB Overview\"}]}");
return result;
}
yes of course, but you should pass a BasicDBObject as parameter, and not a String, like this:
(and your command wasn't formatted correctly, see find command
BasicDBList andList = new BasicDBList();
andList.add(new BasicDBObject("by", "tutorials point"));
andList.add(new BasicDBObject("title", "MongoDB Overview"));
BasicDBObject and = new BasicDBObject("$and", andList);
BasicDBObject command = new BasicDBObject("find", "collectionName");
command.append("filter", and);
mongoTemplate.executeCommand(command);

Java driver: how to get the objectId of an updated object with Mongodb's updateFirst method

I'm trying to get the objectId of an object that I have updated - this is my java code using the java driver:
Query query = new Query();
query.addCriteria(Criteria.where("color").is("pink"));
Update update = new Update();
update.set("name", name);
WriteResult writeResult = mongoTemplate.updateFirst(query, update, Colors.class);
Log.e("object id", writeResult.getUpsertedId().toString());
The log message returns null. I'm using a mongo server 3.0 on mongolab as I'm on the free tier so it shouldn't return null. My mongo shell is also:
MongoDB shell version: 3.0.7
Is there an easy way to return the object ID for the doc that I have just updated? What is the point of the method getUpsertedId() if I cannot return the upsertedId?
To do what I want, I currently have to issue two queries which is highly cumbersome:
//1st query - updating the object first
Query query = new Query();
query.addCriteria(Criteria.where("color").is("pink"));
Update update = new Update();
update.set("name", name);
WriteResult writeResult = mongoTemplate.updateFirst(query, update, Colors.class);
//2nd query - find the object so that I can get its objectid
Query queryColor = new Query();
queryColor.addCriteria(Criteria.where("color").is("pink"));
queryColor.addCriteria(Criteria.where("name").is(name));
Color color = mongoTemplate.findOne(queryColor, Color.class);
Log.e("ColorId", color.getId());
As per David's answer, I even tried his suggestion to rather use upsert on the template, so I changed the code to the below and it still does not work:
Query query = new Query();
query.addCriteria(Criteria.where("color").is("pink"));
Update update = new Update();
update.set("name", name);
WriteResult writeResult = mongoTemplate.upsert(query, update, Colors.class);
Log.e("object id", writeResult.getUpsertedId().toString());
Simon, I think its possible to achieve in one query. What you need is a different method called findAndModify().
In java driver for mongoDB, it has a method called findOneAndUpdate(filter, update, options).
This method returns the document that was updated. Depending on the options you specified for the method, this will either be the document as it was before the update or as it is after the update. If no documents matched the query filter, then null will be returned. Its not required to pass options, in that case it will return the document that was updated before update operation was applied.
A quick look at the mongoTemplate java driver docs here: http://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/FindAndModifyOptions.html tells me that you can use the method call:
public <T> T findAndModify(Query query,
Update update,
FindAndModifyOptions options,
Class<T> entityClass)
You can also change the FindAndModifyOptions class to take on an 'upsert' if the item was not found in the query.If it is found, the object will just be modified.
Upsert only applies if both
The update options had upsert on
A new document was actually created.
Your query neither has upsert enabled, nor creates a new document. Therefore it makes perfect sense that the getUpsertedId() returns null here.
Unfortunately it is not possible to get what you want in a single call with the current API; you need to split it into two calls. This is further indicated by the Mongo shell API for WriteResults:
The _id of the document inserted by an upsert. Returned only if an
upsert results in an insert.
This is an example to do this with findOneAndUpdate(filter,update,options) in Scala:
val findOneAndUpdateOptions = new FindOneAndUpdateOptions
findOneAndUpdateOptions.returnDocument(ReturnDocument.AFTER)
val filter = Document.parse("{\"idContrato\":\"12345\"}")
val update = Document.parse("{ $set: {\"descripcion\": \"New Description\" } }")
val response = collection.findOneAndUpdate(filter,update,findOneAndUpdateOptions)
println(response)

How to code collection find with regex and complex criteria using Java MongoDB driver?

I have the following query in MongoDB:
db.cache.find({objectKey: { $regex: 'Bos*'}, cacheVersionString:'08/03/15_11:05:09'},
{ _id:0, objectData:0, lastModified :0, productCode:0})
Also, I would like to calculate number of records, that is possible in Mongo shell by using count
db.cache.find({objectKey: { $regex: 'Bos*'}, cacheVersionString:'08/03/15_11:05:09'},
{ _id:0, objectData:0, lastModified :0, productCode:0}).count()
How to write the analogous queries in Java using Java MongoDB driver, version 3?
Constructing queries is really just creating BSON document representation, which is basically just the same interface as standard HashMap or List interfaces as appropriate:
Document query = new Document("objectKey",new Document( "$regex","Bos"))
.append("cacheVersionString","08/03/15_11:05:09");
Document projection = new Document("_id",0)
.append("objectData",0)
.append("lastModified",0)
.append("productCode",0);
MongoCursor<Document> cursor = collection.find(query).projection(projection).iterator();
Where that is basically identical to how you are structuring queries in the MongoDB shell.
Alternately you can use builder interfaces if that seems more logical to you:
QueryBuilder builder = QueryBuilder.start();
builder.and("objectKey").regex(Pattern.compile("box"));
builder.and("cache_version_string").is("08/03/15_11:05:09");
BasicDBObject query = (BasicDBObject)builder.get();
Bson projection = Projections.exclude(
"_id",
"obectdata",
"lasModified",
"productCode"
);
MongoCursor<Document> cursor = collection.find(query).projection(projection).iterator();
while (cursor.hasNext()) {
Document doc = cursor.next();
System.out.println(doc.toJson());
}
Both forms essentially contruct the BSON for both the "query" and "projection" components and issue them as arguments to the .find() method. There are also class type definitions if that suits you as well.

Tailable Cursor example in Java using 3.0 driver?

Can someone please provide a complete tailable cursor example in Java? I am using the 3.0 driver and all examples appear to be 2.x. I have only mongo-java-driver-3.0.0.jar in my classpath. I want to get all documents as they are inserted in my capped collection.
//this does not work...
MongoCollection<BasicDBObject> col = database.getCollection(colName, BasicDBObject.class);
DBCursor cur = col.find().sort(new BasicDBObject("$natural", 1))
.addOption(Bytes.QUERYOPTION_TAILABLE)
.addOption(Bytes.QUERYOPTION_AWAITDATA);
// And this does not work...
BasicDBObjectBuilder builder = BasicDBObjectBuilder.start();
builder.add("messageType","STATUS_REQUEST");
DBObject searchQuery = builder.get();
DBObject sortBy = BasicDBObjectBuilder.start("$natural", 1).get();
BasicDBObjectBuilder builderForFields = BasicDBObjectBuilder.start();
DBObject fields = builderForFields.get();
DBCursor cursor = new DBCursor(col, searchQuery, fields, ReadPreference.primary() );
cursor.sort(sortBy);
cursor.addOption(Bytes.QUERYOPTION_AWAITDATA);
cursor.addOption(Bytes.QUERYOPTION_TAILABLE);
//this does work but only returns the messageNumber field. I need the doc.
MongoCursor<Long> c = database.getCollection(colName).distinct("messageNumber", Long.class).iterator();
I see that the MongoCursor interface was added in 3.0. What is that for and does it replace DBCursor?
Thanks a lot
A bit late to the party, but in case you still need help:
find(query).projection(fields).cursorType(CursorType.TailableAwait).iterator();
That code applies to the MongoCollection class.
CursorType is an enum and it has the following values:
Tailable
TailableAwait
Corresponding to the old DBCursor addOption Bytes types:
Bytes.QUERYOPTION_TAILABLE
Bytes.QUERYOPTION_AWAITDATA
I hope that helps.
This is what you might be looking for - EVENT Streaming in MongoDB 3.0.* using new api i.e. 3.0.2
Document query = new Document(); \\here use { indexedField: { $gt: <lastvalue> } index is not used(except for auto deleting documents) but created in capped collection
Document projection = new Document();
MongoCursor<Document> cursor= mongocollection.find(query).projection(projection).cursorType(CursorType.TailableAwait).iterator(); //add .noCursorTimeout(true) here to avoid timeout if you are working on big data
while (cursor.hasNext()){
Document doc = cursor.next();
//do what you want with doc
}
This way mongo cursor will check for new entries in capped collection
In your last line, replace .distinct("messageNumber", Long.class) with .find().
distinct(String fieldName, Class<TResult> resultClass) returns only the unique values of the one field you request.
find() returns all documents of the collection with all of their fields.

How to query mongodb with “like” using the java api?

this question is very similar to another post
I basically want to use the mongodb version of the sql "like" '%m%' operator
but in my situation i'm using the java api for mongodb, while the other post is using mongodb shell
i tried what was posted in the other thread and it worked fine
db.users.find({"name": /m/})
but in java, i'm using the put method on the BasicDBObject and passing it into the find() method on a DBCollections object
BasicDBObject q = new BasicDBOBject();
q.put("name", "/"+m+"/");
dbc.find(q);
but this doesn't seem to be working.
anyone has any ideas?
You need to pass an instance of a Java RegEx (java.util.regex.Pattern):
BasicDBObject q = new BasicDBObject();
q.put("name", java.util.regex.Pattern.compile(m));
dbc.find(q);
This will be converted to a MongoDB regex when sent to the server, as well as any RegEx flags.
You must first quote your text and then use the compile to get a regex expression:
q.put("name", Pattern.compile(Pattern.quote(m)));
Without using java.util.Pattern.quote() some characters are not escaped.
e.g. using ? as the m parameter will throw an exception.
To make it case insensitive:
Document doc = new Document("name", Pattern.compile(keyword, Pattern.CASE_INSENSITIVE));
collection.find(doc);
In spring data mongodb, this can be done as:
Query query = new Query();
query.limit(10);
query.addCriteria(Criteria.where("tagName").regex(tagName));
mongoOperation.find(query, Tags.class);
Document doc = new Document("name", Pattern.compile(keyword));
collection.find(doc);
Might not be the actual answer, ( Executing the terminal query directly )
public void displayDetails() {
try {
// DB db = roleDao.returnDB();
MongoClient mongoClient = new MongoClient("localhost", 5000);
DB db = mongoClient.getDB("test");
db.eval("db.test.update({'id':{'$not':{'$in':[/su/]}}},{$set:{'test':'test3'}},true,true)", new Object[] {});
System.out.println("inserted ");
} catch (Exception e) {
System.out.println(e);
}
}
if(searchType.equals("employeeId"))
{
query.addCriteria(Criteria.where(searchType).regex(java.util.regex.Pattern.compile(searchValue)));
employees = mongoOperations.find(query, Employee.class, "OfficialInformation");
}

Categories

Resources