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 :)
Related
I am working on this legacy application (7 years old). I have many methods that do the same thing that I am trying to upgrade to a newer MongoDB Java driver, but it won't compile.
#Override
public void saveOrUpdatePrinter(Document printer) {
printer.put(PRINTER_COLUMNS.updateDate,new Date());
MongoCollection<Document> collection = mongoTemplate.getCollection("PRINTERS");
printer.remove("_id");
Document query = new Document().append(PRINTER_COLUMNS.internal_id, printer.get(PRINTER_COLUMNS.internal_id));
WriteResult result = collection.update(query, printer, true, false);
logger.debug("saveOrUpdatePrinter updeded records: " + result.getN());
}//
The error is:
The method update(Document, Document, boolean, boolean) is undefined
for the type MongoCollection<Document>
Why was this removed?
printer.remove("_id");
Also I would like to know how to do either update or save on the document in one go?
And what will be the proper way to update a single document in the new (MongoDB Java driver 4.7.0)?
Reading this code a little more seems like it was an attempt to do UPSERT operation (update or insert).
I will try to answer your questions.
Q : How to do either Update or Save on the Document in one go?
-> MongoDB's update method updates the values in the existing document whereas the save method replaces the existing document with the document passed. Nothing happens in one go.
update method only updates which are specific fields which are modified by comparing the fields from the modified document with the original document whereas the save method updates/replaces the values of all the fields of an original document by the taking values from the modified document and setting the values into the original document.
Q : What will be the proper way to update a single document in the new (Mongo Java driver 4.7.0)
-> You should be using updateOne(query, updates, options) to update a single document on a MongoCollection object.
From updateOne docs :
The method accepts a filter that matches the document you want to
update and an update statement that instructs the driver how to change
the matching document. The updateOne() method only updates the first
document that matches the filter.
To perform an update with the updateOne() method, you must pass a
query filter and an update document. The query filter specifies the
criteria for which document to perform the update on and the update
document provides instructions on what changes to make to it.
You can optionally pass an instance of UpdateOptions to the
updateOne() method in order to specify the method's behavior. For
example, if you set the upsert field of the UpdateOptions object to
true, the operation inserts a new document from the fields in both the
query and update document if no documents match the query filter.
Q : Is it seems like it was an attempt to do UPSERT operation (Update or Insert) ?
-> Yes, it's an upsert operation.
Q : Why the code is trying to remove _id from document ?
-> The update method will update the document if the document was found by internal_id. If the document was not found and also if there is no _id field in the document, then the mongoshell will consider it as a new document and will invoke insert method internally via the update method to insert the document. For the insertion to happen, that's why it was removed from document.
Just update the code to this.
#Override
public void saveOrUpdatePrinter(Document printer) {
MongoCollection<Document> collection = mongoTemplate.getCollection("PRINTERS");
Document query = new Document().append(PRINTER_COLUMNS.internal_id, printer.get(PRINTER_COLUMNS.internal_id));
UpdateOptions options = new UpdateOptions().upsert(true);
printer.put(PRINTER_COLUMNS.updateDate,new Date());
UpdateResult result = collection.updateOne(query, printer, options);
logger.debug("saveOrUpdatePrinter updated records: " + result.getModifiedCount());
}
You can update a document using the MongoCollection#updateOne() method
An example would be:
collection.updateOne(Filters.eq("_id", new ObjectId("1234")), Updates.set("date", new Date());
The following code allows us to update all documents in customerDetail collection where customer_user_id is 1:
db.getCollection("customerDetail")
.updateMany(Filters.eq("customer_user_id", 1),
Updates.combine(
Updates.set("birth_year", "birth_year"),
Updates.set("country", "country")
));
but I need to update ALL documents in the collection, so I need to find a way how to ask Java Driver do not apply any filters to update query, but as I can see for updateMany method Filter is a mandatory attribute and I can't just pass null.
So how can I update all documents?
One option which I use frequently
mongoCollectionObject
.updateMany(new Document(), //
new Document("$set"
new Document("birth_year", "birth_year")
.append("country", "country")
));
First one is the condition - as it is empty - equivalent to {} - means all documents
second one is the document to be set for all matching documents
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.
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'), ...
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)
)