Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongodb upsert only update selected fields, but insert all

Tags:

mongodb

upsert

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:

  • I query for a single unique value
  • If a document already exists, only a timestamp value (lets call it 'lastseen') is updated to a new value
  • If a document does not exists, I will add it with a long list of different key/value pairs that should remain static for the remainder of its lifespan.

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:

  • The correct update behavior, but would insert a document with only a subset of the desired fields if document does not exist
  • The correct insert behavior, but would then overwrite all existing fields if document already exists

Are my understanding correct? If so, is this possible to solve with a single operation?

like image 909
agnsaft Avatar asked Dec 28 '12 12:12

agnsaft


People also ask

What is the difference between update and Upsert in MongoDB?

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.

Is there an Upsert option in the MongoDB insert command?

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.

How do you update Upsert?

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.

How to query to update only certain fields in MongoDB?

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 −

What is upsert in MongoDB and how does it work?

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:

How to prevent MongoDB from inserting the same document more than once?

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}}, {

Why does the update () method insert a new document with two fields?

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.


2 Answers

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}
)
like image 87
cerberos Avatar answered Oct 21 '22 23:10

cerberos


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.

like image 31
Sammaye Avatar answered Oct 22 '22 01:10

Sammaye