Skip to content

Instantly share code, notes, and snippets.

@rantav
Created June 27, 2012 05:18
Show Gist options
  • Save rantav/3001646 to your computer and use it in GitHub Desktop.
Save rantav/3001646 to your computer and use it in GitHub Desktop.
MongoDB increment or insert

In mongodb it's easy to make at upsert, meaning update-or-insert by calling

db.collection.update({criteria}, {updated fields}, true)

The third parameter means - insert a new document if the document doesn't exist yet. So, for example, the following will insert a new document for the user if there's no document for that user yet, and will update it if it already exists:

 db.users.update({user_id: '1234'}, {user_id: '1234', name: 'Ran'}, true)

But What If - you want to - not insert a predefined value, but instead - increment a counter? You have a visit_count for each user, and you'd like to increment that count if there's already a document for that user's visit count, or insert 1 if it's the first time. Ideally, you'd like to do something like this:

db.users.update({user_id: '1234'}, {user_id: '1234', $inc: {visit_count: 1}}, true)

Unfortunately, however, mongo doesn't work like this. Mongo does not allow upserts in combination with $inc (or other atomic operations). Atomic operations are nice b/c you're guaranteed that the counter's (in this case counter) value will remain consistent in light of multiple concurrent updates. So how do you make an "increment if the document already exists, and insert if it doesn't"?

Here's the trick I found out yesterday (and to be fair, I'm pretty green to mongo, so maybe there's a better one). Please see the file mongo-insert-or-incr.js below.

var id = '1234';
db.users.insert({_id: id, visit_count: 1});
lastError = db.getLastError();
if (lastError) {
// document already exists, so just increment the count
db.users.update({_id: id}, {$inc: {visit_count: 1}})
}
@PDS42
Copy link

PDS42 commented Oct 24, 2019

@zsf3 : You can try setOnInsert with upsert to achieve that.

Very helpful answer, thank you for that. Achieved exactly what I wanted

@nolanamy
Copy link

nolanamy commented Jan 20, 2020

Yeah MongoDB (I'm using 3.6) happily starts at 0 for you if the value doesn't exist:

db.items.drop()

db.items.update({ _id: 1 }, {
  $inc: { 'counters.a': 1 }
}, { upsert: true })

// upserts:
// { "_id" : 1, "counters" : { "a" : 1 } }

db.items.update({ _id: 1 }, {
  $inc: { 'counters.b': 1 }
}, { upsert: true })

// modifies:
// { "_id" : 1, "counters" : { "a" : 1, "b" : 1 } }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment