I am trying to use upsert in MongoDB to update a single field in a document if found OR insert a whole new document with lots of fields. The problem is that it appears to me that MongoDB either replaces every field or inserts a subset of fields in its upsert operation, i.e. it can not insert more fields than it actually wants to update.
What I want to do is the following:
Lets illustrate:
This example would from my understanding update the 'lastseen' date if 'name' is found, but if 'name' is not found it would only insert 'name' + 'lastseen'.
db.somecollection.update({name: "some name"},{ $set: {"lastseen": "2012-12-28"}}, {upsert:true})
If I added more fields (key/value pairs) to the second argument and drop the $set, then every field would be replaced on update, but would have the desired effect on insert. Is there anything like $insert or similar to perform operations only when inserting?
So it seems to me that I can only get one of the following:
Are my understanding correct? If so, is this possible to solve with a single operation?
Upsert is a combination of insert and update (inSERT + UPdate = upsert). We can use the upsert with different update methods, i.e., update, findAndModify, and replaceOne. Here in MongoDB, the upsert option is a Boolean value. Suppose the value is true and the documents match the specified query filter.
Since upsert is defined as operation that "creates a new document when no document matches the query criteria" there is no place for upserts in insert command. It is an option for the update command.
Or in other words, upsert is a combination of update and insert (update + insert = upsert). If the value of this option is set to true and the document or documents found that match the specified query, then the update operation will update the matched document or documents.
MongoDB query to update only certain fields? To update only certain fields, use $set. Let us create a collection with documents − Display all documents from a collection with the help of find () method −
If your application stores and modifies data in MongoDB, you probably use insert and update operations. In certain workflows, you may need to choose between an insert and update depending on whether the document exists. In these cases, you can streamline your application logic by using the upsert option available in the following methods:
Note: To prevent MongoDB from inserting the same document more than once, create a unique index on the name field. With a unique index, if multiple documents want the same update with upsert: true, only one update operation successfully inserts a new document. db.Collection_name.update ( {Selection_criteria}, {$set: {Update_data}}, {
Here, no document matches the name “Priya”, so the update () method inserts a new document that contains two fields (i.e., name: “Priya” and department: “HR”) because the value of the upsert option is set to true.
MongoDB 2.4 has $setOnInsert
db.somecollection.update(
{name: "some name"},
{
$set: {
"lastseen": "2012-12-28"
},
$setOnInsert: {
"firstseen": <TIMESTAMP> # set on insert, not on update
}
},
{upsert:true}
)
There is a feature request for this ( https://jira.mongodb.org/browse/SERVER-340 ) which is resolved in 2.3. Odd releases are actually dev releases so this will be in the 2.4 stable.
So there is no real way in the current stable versions to do this yet. I am afraid the only method is to actually do 3 conditional queries atm: 1 to check the row, then a if
to either insert or update.
I suppose if you had real problems with lock here you could do this function with sole JS but that's evil however it would lock this update to a single thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With