mongodb: upserting: only set value if document is being inserted

I ran into a very similar problem when attempting to upsert documents based on existing content--maybe this solution will work for you also:

Try removing the _id attribute from your record and only use it in the query portion of your update (you'll have to translate from pymongo speak...)

myid = doc.get('_id')
del doc['_id']
mycollection.update({'_id':myid}, {'$set':doc}, upsert=True)

If you will trigger the following code 2 subsequent times, it will first set both firstVisit and lastVisit on document insert (and will return upsertedId in the response) and on the second it will only update lastVisit (and will return modifiedCount: 1).

Tested with Mongo 4.0.5 though I believe should be working with older versions.

db.collection.updateOne(
  {_id: 1}, 
  { 
    $set: { 
      lastVisit: Date.now() 
    }, 
    $setOnInsert: {
      firstVisit: Date.now()
    }
  }, 
  { upsert: true }
);

I ran into the exact same problem and there was no simple solution for <2.4 however since 2.4 the $setOnInsert operator let's you do exactly that.

db.collection.update( <query>,
                      { $setOnInsert: { "firstTime": <TIMESTAMP> } },
                      { upsert: true }
                    )

See the 2.4 release notes of setOnInsert for more info.

Tags:

Mongodb