Mehdi Yeganeh
Mehdi Yeganeh

Reputation: 2129

How can i have auto-increment field in nedb?

I want to have exactly auto-increment field like relational or objective databases, so i need an integer _id field with automatically set field value, value should be one more last record _id value like this:

data:

{_id:1,name"foo"}
{_id:2,name"bar"}

remove last record:

{_id:1,name"foo"}

add new record:

{_id:1,name"foo"}
{_id:3,name"newbar"}

I added a function to my datastore and calculate maximum of _id and plus 1 max(_id)+1 and set as field value, but there is problem here:

When we use auto-increment field in relational databases, it works like i said and after you remove last record it reserved a deleted record number and new inserted records continue increment but in my way its says the _id of removed record for new record.

My code is:

var Datastore = require('nedb'),
localDb = new Datastore({
    filename: __dirname + '/dbFilePath.db',
    autoload: true
});

localDb.getMax = function(fieldName, onFind){
   db.find({}).sort({_id:-1}).limit(1).exec(function (err, docs) {onFind && onFind(err, docs['_id']);});
   return localDb;
}

localDb.insertAutoId = function(data, onAdd){
    var newIndex = 0;
    localDb.getMax(function (err, maxValue) {
        newIndex = maxValue+1;

        if(!data["_id"])
            data["_id"] = newIndex;

        localDb.insert(data, function (err, newDoc) {
            onAdd && onAdd(err, newDoc);
        });
    });
    return localDb;
}

Upvotes: 2

Views: 4484

Answers (3)

Júlio Jamil
Júlio Jamil

Reputation: 107

I do not know if it will be useful for you anymore I use a database to store the next ids, inspired in the mysql system. Who always reserves the next id. So I created a function that verifies if there is an id to the db, if it does not, it add with the value "1", and when it updates it looks for and if it exists and it performs the sequence. This gave me full control over my ids. The schema would be:

{
name: nameDb,
nextId: itemID
}

If you want you can create functions for updating documents, versioning, etc.

example:

db.autoincrement = new Datastore({filename: 'data/autoincrement.db', autoload: true});

function getUniqueId(nameDb, cb) {
    db.autoincrement.findOne({name: nameDb}, function (err, doc) {
        if (err) {
            throw err;
        } else {
            if (doc) {
                const itemID = doc.nextId + 1;
                db.autoincrement.update({name: nameDb}, {
                    name: nameDb,
                    nextId: itemID
                }, {}, function (err, numReplaced) {
                    db.autoincrement.persistence.compactDatafile();
                    if (err) {
                        throw err;
                    } else {
                        // console.log(numReplaced);
                    }
                    cb(doc.nextId);
                });
            } else {
                const data = {
                    name: nameDb,
                    nextId: 2
                };

                db.autoincrement.insert(data, function (err, newDoc) {
                    if (err) {
                        throw err;
                    } else {
                        // console.log(newDoc);
                    }
                    cb(1);
                });
            }
        }

    });
}

insert new document example:

       function insert(req, cb) {
        getUniqueId("testdb", function (uniqueId) {
            data.itemId = uniqueId;

            db.testdb.insert(data, function (err, newDoc) {
                if (err) {
                    cb({error: '1', message: 'error#2'});
                    throw err;
                }
                cb({error: '0', message: 'Item add'});
            });

        });
       }

Upvotes: 1

stdob--
stdob--

Reputation: 29172

You can store the last value of the index in the database. Something like this:

var Datastore = require('nedb');
var db = new Datastore({ 
  filename: __dirname + '/dbFilePath.db', 
  autoload: true 
});

// Initialize the initial index value
// (if it already exists in the database, it is not overwritten)
db.insert({_id: '__autoid__', value: -1});

db.getAutoId = function(onFind) {
  db.findOne( { _id: '__autoid__' }, function(err, doc) {
    if (err) {
      onFind && onFind(err)
    } else {
      // Update and returns the index value
      db.update({ _id: '__autoid__'}, { $set: {value: ++doc.value} }, {},
         function(err, count) {
           onFind && onFind(err, doc.value);
      });
    }
  });
  return db;
}

Upvotes: 3

daniel.gindi
daniel.gindi

Reputation: 3496

An improved answer for nedb would be:

db.getAutoincrementId = function (cb) {
    this.update(
        { _id: '__autoid__' },
        { $inc: { seq: 1 } },
        { upsert: true, returnUpdatedDocs: true },
        function (err, affected, autoid) { 
            cb && cb(err, autoid.seq);
        }
    );
    return this;
};

Which is equivalent to the mongodb way:

db.getAutoincrementId = function (cb) {
    this.findAndModify({
            query: { _id: '__autoid__' },
            update: { $inc: { seq: 1 } },
            new: true
        }
        function (err, autoid) { 
            cb && cb(err, autoid.seq);
        }
    );
    return this;
};

Upvotes: 5

Related Questions