Shrey Gupta
Shrey Gupta

Reputation: 37

Mongodb upsert inserting when it should have updated

I am using an upsert query to insert/update a document in a collection, however the query not always reliably upserts. It sometimes inserts another document when it should have updated. You can see the query below - Updated query after Alex pointed it out -

db.test.update(
      { departmentID: "1",
        storeID: "1",
        customerID: "1"},
      {  
         $set: { 
           name: "Andy",
           rating: 1,
           score: 1
         },
         $setOnInsert: { 
             departmentID: "1",
             storeID: "1",
             customerID: "1"
         }
      },
      { upsert: true }
   );

This query mostly works, but sometimes what ends up happening is when the above query is run in quick succession(gap of 0.004 seconds), the query ends up inserting 2 documents with departmentID-1, storeID-1 and customerID-1, whereas it should have inserted only one document and updated on the second instance.

Upvotes: 0

Views: 810

Answers (1)

Alex Blex
Alex Blex

Reputation: 37018

https://docs.mongodb.com/manual/reference/method/db.collection.update/#use-unique-indexes is quite clear about it:

To avoid inserting the same document more than once, only use upsert: true if the query field is uniquely indexed.

Update

There are few other problems with the query, thanks to Neil Lunn pointing it out. The replace document syntax used in the query results with following document being inserted:

{
    "_id" : ObjectId(....),
    "name" : "Andy",
    "rating" : 1.0,
    "score" : 1.0
}

This document doesn't have any departmentID, storeID, or customerID and won't match the filter on consecutive calls of the update query. I.e. Running the same query 5 times on an empty collection will result with 5 documents inserted.

The correct query should use update individual fields syntax with combination of $set and $setOnInsert:

db.test.update(
   { departmentID: "1",
     storeID: "1",
     customerID: "1"},
   {  
      $set: { 
        name: "Andy",
        rating: 1,
        score: 1
      },
      $setOnInsert: { 
          departmentID: "1",
          storeID: "1",
          customerID: "1"
      }
   },
   { upsert: true }
);

Upvotes: 1

Related Questions