How to update a document in MongoDB using ObjectID in Java - java

What I am trying to accomplish here is pretty simple. I am trying to update a single document in MongoDB collection. When I look up the document using any field, such as "name", the update query succeeds. Here is the query:
mongoDB.getCollection("restaurants").updateOne(
new BasicDBObject("name", "Morris Park Bake Shop"),
new BasicDBObject("$set", new BasicDBObject("zipcode", "10462"))
);
If I try to lookup the document with the ObjectId, it never works as it doesn't match any document.
mongoDB.getCollection("restaurants").updateOne(
new BasicDBObject("_id", "56110fe1f882142d842b2a63"),
new BasicDBObject("$set", new BasicDBObject("zipcode", "10462"))
);
Is it possible to make this query work with Object IDs?
I agree that my question is a bit similar to How to query documents using "_id" field in Java mongodb driver? however I am not getting any errors while trying to update a document. It just doesn't match anything.

You're currently trying to update based on a string, not an ObjectId.
Make sure to initialise a new ObjectId from the string when building your query:
mongoDB.getCollection("restaurants").updateOne(
new BasicDBObject("_id", new ObjectId("56110fe1f882142d842b2a63")),
new BasicDBObject("$set", new BasicDBObject("zipcode", "10462"))
);

#sheilak's answer is the best one but,
You could use {"_id", {"$oid","56110fe1f882142d842b2a63"}} as the filter for the update query if you want it to be in the string format

Convert the string to objectid:
from bson.objectid import ObjectId
db.collection.find_one({"_id":ObjectId('5a61bfadef860e4bf266edb2')})
{u'_id': ObjectId('5a61bfadef860e4bf266edb2'), ...

Related

Get the object id after inserting the mongodb document in java

I am using mongodb 3.4 and I want to get the last inserted document id. I have searched all and I found out below code can be used if I used a BasicDBObject.
BasicDBObject docs = new BasicDBObject(doc);
collection.insertOne(docs);
ID = (ObjectId)doc.get( "_id" );
But the problem is am using Document type not BasicDBObject so I tried to get it as like this, doc.getObjectId();. But it asks a parameter which I actually I want, So does anyone know how to get it?
EDIT
This is the I am inserting it to mongo db.
Document doc = new Document("jarFileName", jarDataObj.getJarFileName())
.append("directory", jarDataObj.getPathData())
.append("version", jarDataObj.getVersion())
.append("artifactID", jarDataObj.getArtifactId())
.append("groupID", jarDataObj.getGroupId());
If I use doc.toJson() it shows me whole document. is there a way to extract only _id?
This gives me only the value i want it like the objectkey, So I can use it as reference key.
collection.insertOne(doc);
jarID = doc.get( "_id" );
System.out.println(jarID); //59a4db1a6812d7430c3ef2a5
Based on ObjectId Javadoc, you can simply instantiate an ObjectId from a 24 byte Hex string, which is what 59a4db1a6812d7430c3ef2a5 is if you use UTF-8 encoding. Why don't you just do new ObjectId("59a4db1a6812d7430c3ef2a5"), or new ObjectId("59a4db1a6812d7430c3ef2a5".getBytes(StandardCharsets.UTF_8))? Although, I'd say that exposing ObjectId outside the layer that integrates with Mongo is a design flaw.

Does mongo-hadoop support replacing documents?

I'm trying to replace (not update with $set) documents in MongoDB using mongo-hadoop in Spark (mongo-hadoop-core-1.4.2.jar & mongo-java-driver-3.2.1.jar) :
BasicDBObject query = new BasicDBObject();
query.append("_id", 6972);
BasicDBObject update = new BasicDBObject();
update.append("_id", 6988);
update.append("f1", "ACTIVE_USER");
Then I'm writing something like this :
new MongoUpdateWritable(query, update, false, true);
But this is failing with :
Caused by: java.lang.IllegalArgumentException: Invalid BSON field name f1
I can do :
new MongoUpdateWritable(query, new BasicDBObject("$set", update), false, true);
But I want to replace the whole document.
Update:
mongo-hadoop added support for replacing documents in 2.0.0-rc0. From then on, to replace a document entirely, you'll have to use
new MongoUpdateWritable(query, update, false/*or true*/, false, true)
Note: you can't use replacing and multiUpdate = true together, and replacing also doesn't change the _id value - see Replace a Document Entirely:
The update() method does not replace the _id value.
...
update() cannot update multiple documents.
Looking at the code, that doesn't seem to be possible: MongoOutputCommitter always issues an update command (that can only contain $operators) - see MongoOutputCommitter.java line 155 and below. They use BulkUpdateRequestBuilder's update / updateOne methods, but to issue a replace command they need to use replaceOne method.
So, no such feature. Maybe you'll make a pull request :)

How to upsert document in MongoDB Java driver 3

what is the idiomatic way to upsert a document using version 3 of the mongodb java driver (specifically v3.0.1)?
We have a collection for sessions and when a new session gets created or modified, we want to upsert it in one operation - rather than having to query if a document exists yet and then either inserting or replacing.
Our old upsertion code used the scala driver casbah 2.7.3. It looked like:
import com.mongodb.casbah.MongoCollection
import com.mongdb.DBObject
val sessionCollection: MongoCollection = ...
val sessionKey: String = ...
val sessionDocument: DBObject = ... // Either create a new one, or find and modify an existing one
sessionCollection.update(
"_id" -> sessionKey,
sessionDocument
upsert = true
)
In our current project we're just using the plain java 3.0.1 driver and we're using BsonDocument instead of DBObject to make it more typsafe. I tried to replace the above with something like:
import com.mongodb.client.MongoCollection
val sessionCollection: MongoCollection = ...
val sessionKey: String = ...
val sessionDocument: BsonDocument = // Either create a new one, or find and modify an existing one
val updateOptions = new UpdateOptions
updateOptions.upsert(true)
sessionCollection.updateOne(
"_id" -> new BsonString(sessionKey),
sessionDocument,
updateOptions
)
This throws the error "java.lang.IllegalArgumentException: Invalid BSON field name ...". The error is covered in this question but the op in that question wasn't trying to upsert in one operation - they were using context to decide whether to replace/update/insert etc...
I'm happy with code samples in scala or java.
Thanks!
In the Mongo Java Driver 3.0 series we added a new Crud API which is more explicit and therefore beginner friendly. This initiative has been rolled out over a number of MongoDB Drivers but it does contain some changes compared to the older API.
As you are not updating an existing document using an update operator, the updateOne method is not appropriate.
The operation you describe is a replaceOne operation and can be run like so:
sessionCollection.replaceOne(
"_id" -> new BsonString(sessionKey),
sessionDocument,
(new UpdateOptions()).upsert(true)
)

Mongo insert $currentDate in Java Driver

I've got a question about $currentDate
What is the best way to insert a document in mongo db so that it contains the "server time" (like ''now()'' in some RDBMSs) using the Java Driver?
For example, lest say I have a document like:
{
name : "John",
birthday : <$currentDate_goes_here>
}
What I want is to insert the document so that the evaluation of the date would be done by mongo server at the time of insertion on the server side.
This is critical because our servers might not be totally synchronized and there is a need to have the time we can rely on (for example the time on mongo server).
I'm using a standard java driver for mongo, so any code snippet in Java will be more than welcome.
This is what I've tried so far
MongoClient mongoClient = new MongoClient();
DB sampleDB = mongoClient.getDB("sampleDB");
BasicDBObject update =
new BasicDBObject("$set", new BasicDBObject("name","john")
.append("$currentDate", new BasicDBObject("birthday",true)));
sampleDB.getCollection("col1").insert(update);
This thing fails on the following exception:
java.lang.IllegalArgumentException: Document field names can't start with '$' (Bad Key: '$set')
at com.mongodb.DBCollection.validateKey(DBCollection.java:1845)
at com.mongodb.DBCollection._checkKeys(DBCollection.java:1803)
at com.mongodb.DBCollection._checkObject(DBCollection.java:1790)
at com.mongodb.DBCollectionImpl.applyRulesForInsert(DBCollectionImpl.java:392)
at com.mongodb.DBCollectionImpl.insertWithCommandProtocol(DBCollectionImpl.java:381)
at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:186)
at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:165)
at com.mongodb.DBCollection.insert(DBCollection.java:93)
at com.mongodb.DBCollection.insert(DBCollection.java:78)
at com.mongodb.DBCollection.insert(DBCollection.java:120)
In which case the answer is fairly simple. It is really about serializing from java BasicDBObject classes to the basic MongoDB interpretation. Without respect to your actual "query" document the "update" document part of your statement should be:
BasicDBObject update = new BasicDBObject("$set", new BasicDBObject("name","john")
.append("$currentDate", new BasicDBObject("birthrhday",true))
;
Which will indeed use the "server time" at the point of "update insertion" or "modification" with respect to the $currentDate modifier as used.
Just to be clear here, you don't use the .insert() method but an "upsert"operation with .insert(). The "query" and "update" syntax applies. Also see the $setOnInsert operator for specifically not modifying existing documents.
You can also use aggregation variable "$$NOW" if you are using an aggregation pipeline with update method.
MongoClient mongoClient = new MongoClient();
DB sampleDB = mongoClient.getDB("sampleDB");
BasicDBObject update =
new BasicDBObject("$set", new BasicDBObject("name","john")
.append("birthday", new BsonString("$$NOW")));
sampleDB.getCollection("col1").updateOne(query, List.of(update));
You can also use "$$NOW" with aggregation operators such as $add, $subtract, and many more, to compute more specific values (including dates) on the database side.
If you want to pass the Application Server's time instead of Database time, use the following code to send the current time. You should decide whether to use this in case if the Application Server time differs from Database Server time.
new BsonDateTime(Instant.now().toEpochMilli())
Sample Code:
MongoClient mongoClient = new MongoClient();
DB sampleDB = mongoClient.getDB("sampleDB");
BasicDBObject update =
new BasicDBObject("$set", new BasicDBObject("name","john")
.append("birthday", new BsonDateTime(Instant.now().toEpochMilli())));
sampleDB.getCollection("col1").updateOne(query, update);

Java equivalent for a MongoDB select query

I would like to retrieve the following information:
select names from database where names like 'Jon';
but for MongoDB in Java. Essentially, it should return all names that contain the word Jon in them, like Jonathan, Jong etc etc. I know that there is the $in operator in MongoDB, but how do I do the same in Java, using the Java driver? I've been trying to look for it everywhere but am getting nothing. I've tried: query = new BasicDBObject("names", new BasicDBObject("$in", "Jon"));, and query = new BasicDBObject("names", new BasicDBObject("$in", Jon));
But neither of them worked :( Please help!
The MongoDB Java driver equivalent of that SELECT statement would be:
BasicDBObject fields = new BasicDBObject().append("name", 1); // SELECT name
BasicDBObject query = new BasicDBObject().append("name", "Jon"); // WHERE name = "Jon"
DBCursor results = yourCollection.find(query, fields); // FROM yourCollection
When you want to search for a part of a string, you can use the $regex operator:
query = new BasicDBObject("name", new BasicDBObject("$regex", "Jon"));
This will get you all objects where the name matches the regular expression Jon, which is everything which includes the string "Jon" anywhere.
Check the Mongo-Java official site, plus a nice library for mapping mongo objects
The $in operator in MongoDB resembles the IN operator in SQL. For instance, it can be used for executing SQL-like queries as
SELECT * FROM table WHERE id IN {1, 4, 6, 7, 9}
This is why it doesn't work for you. Use Regular expressions, as the others have already suggested.

Categories