TIMEX
TIMEX

Reputation: 271614

How do you implement an auto-incrementing primary ID in MongoDB?

Just like in MYSQL, I want an incrementing ID.

Upvotes: 10

Views: 13594

Answers (7)

Chris Heald
Chris Heald

Reputation: 62638

You'll need to use MongoDB's findAndModify command. With it, you can atomically select and increment a field.

db.seq.findAndModify({
  query: {"_id": "users"},
  update: {$inc: {"seq":1}},
  new: true
});

This will increment a counter for the users collection, which you can then add to the document prior to insertion. Since it's atomic, you don't have to worry about race conditions resulting in conflicting IDs.

It's not as seamless as MySQL's auto_increment flag, but you also usually have the option of specifying your own ID factory in your Mongo driver, so you could implement a factory that uses findAndModify to increment and return IDs transparently, resulting in a much more MySQL-like experience.

The downside of this approach is that since every insert is dependent on a write lock on your sequence collection, if you're doing a lot of writes, you could end up bottlenecking on that pretty quickly. If you just want to guarantee that documents in a collection are sorted in insertion order, then look at Capped Collections.

Upvotes: 21

Nishchit
Nishchit

Reputation: 19074

MongoDB provides 2 way to auto increment _id (or custom key) .

Counter Collection


Here we need to create collection which stores the maximum number of keys and increment by 1 every time when we call this function.

1. STORE FUNCTION

function getNextSequence(collectionName) {
   var ret = db.counters.findAndModify({
               query: { _id: collectionName },
               update: { $inc: { seq: 1 } },
               new: true,
               upsert: true
             });

   return ret.seq;
}

2. INSERT DOC

db.users.insert({
  _id: getNextSequence("USER"),
  name: "Nishchit."
})

Optimistic Loop


In this pattern, an Optimistic Loop calculates the incremented _id value and attempts to insert a document with the calculated _id value. If the insert is successful, the loop ends. Otherwise, the loop will iterate through possible _id values until the insert is successful.

1. STORE FUNCTION

function insertDocument(doc, targetCollection) {

    while (1) {

        var cursor = targetCollection.find( {}, { _id: 1 } ).sort( { _id: -1 } ).limit(1);

        var seq = cursor.hasNext() ? cursor.next()._id + 1 : 1;

        doc._id = seq;

        var results = targetCollection.insert(doc);

        if( results.hasWriteError() ) {
            if( results.writeError.code == 11000 /* dup key */ )
                continue;
            else
                print( "unexpected error inserting data: " + tojson( results ) );
        }

        break;
    }
}

2. INSERT DOC

var myCollection = db.USERS;

insertDocument(
   {
     name: "Nishchit Dhanani"
   },
   myCollection
);

Official doc from MongoDB.

Upvotes: 3

rahulroy9202
rahulroy9202

Reputation: 2848

I am using this - mongoose-auto-increment

var mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    autoIncrement = require('mongoose-auto-increment');

var connection = mongoose.createConnection("mongodb://localhost/myDatabase");

autoIncrement.initialize(connection);

var bookSchema = new Schema({
    author: { type: Schema.Types.ObjectId, ref: 'Author' },
    title: String,
    genre: String,
    publishDate: Date
});

bookSchema.plugin(autoIncrement.plugin, 'Book');
var Book = connection.model('Book', bookSchema);

Upvotes: 0

Basav
Basav

Reputation: 3406

@TIMEX : Check if below link can help you, if you were looking for a sequence number not ID (coz ID is reserved by mongo)

http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/#auto-increment-counters-collection

@Dennis Burton Auto increment if user does will it not cause collision? i feel, hence mongo db uses its own _Id so it can avoid collision, but if user wishes to have a column as a running sequence they are free to have it

Upvotes: 0

Froyke
Froyke

Reputation: 41

If you suspect your data could span more than a single server (aka shards) then go with Dennis and use the native ObjectId.

If you prefer int/long id (looks better on urls) then you can start with naive implementation of a generator using the findAndModify as Chris suggested. When/if the performance/locking starts to be an issue you can upgrade your generator to implement Hi/Lo algorithm. This will result much less stress on the 'seq' collection. and practically eliminate this issue. (the client side generator is using a 'pool' and only contact the DB when it has no more free ids)

Upvotes: 1

Dmitri
Dmitri

Reputation: 36280

While auto increment is not supported, you can easily implement your own little class for issuing incremental values.

I needed that feature myself, so I wrote a small class in php. I wrote about it on my blog, here, take a look here

Upvotes: 0

Dennis Burton
Dennis Burton

Reputation: 3332

MongoDB is intended to be scaled horizantally. In this case, an auto increment would lead to id collisions. That is why the id looks much more like a guid/uuid.

Upvotes: 14

Related Questions