Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use auto increment in sails-mongo

I was just playing around the concepts of sailsjs then I came to know we cannot use auto increments in sails if we are using mongodb as our database. I cannot able to use the auto increments even for the non primary key attributes. Is there any special methods to use auto increments operations for an attribute which is not a primary key? Thanks in advance

like image 567
Anandapriyan S.D Avatar asked Dec 01 '22 17:12

Anandapriyan S.D


2 Answers

If waterline doesn't support it automatically, which is what it seems like, you can do it in the beforeCreate lifecycle callback of waterline. It is independent of any database adapter.

I would recommend you to take a look at how lifecycle callbacks work for clear understanding. Workflow would be something like following. Before creating any record you would check the count of records of the Model. Then update the x field of the records to be created as one more than that found count and pass the batton.

beforeCreate: function(obj, next){
    Model.count().exec(function(err, cnt){
        if(err) next(err);
        else{
            obj['x'] = cnt + 1;
            next(null);
        }
    })
}

Counting the records is not the perfect way. You can change the way you like to find the value of auto-incremented value. Purpose of this example is to give you intuition of how it can be done. This is not the exact alternative of autoincrement but it's an effective workaround I guess. Hope it helps you.

like image 109
taufique Avatar answered Dec 06 '22 20:12

taufique


There are different strategies, how you can create auto increment sequences with mongo. You can find the general information in the official documentation http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/

Here is an adaptation of the first approach for sails.js waterline, which uses counter collection. First you have to create a Sequence Model and implement a get next method.

module.exports = {
    attributes : {
        num : {
            type : "integer"
        },
    },

    next : function (id, cb) {

        Sequence.native(function (err, col) {

            col.findAndModify(
                { _id: id },
                [['_id', 'asc']],
                {$inc: { num : 1 }},
                { new: true, upsert : true}
                , function(err, data) {

                    cb(err, data.value.num);
                });

        });

    },
};

Since waterline doesn't support findAndModify functionality of mongodb, you have to make use of native driver method. It looks bit weird, but it works. More about it here.

And then you can just call the Sequence.next() in the beforeCreate lifecycle callback method of your model to get next auto increment value for the new collection document.

// Model Order, for Example.
module.exports = {

    attributes: {

        number: {
            type: "integer"
        },
        // other attributes
    },

    // add auto increment value for "number" before create a document
    beforeCreate : function (values, cb) {

        // add seq number, use
        Sequence.next("order", function(err, num) {

            if (err) return cb(err);

            values.number = num;

            cb();
        });
    }

    // your other methods ...
};

I know it is a bit late, but I just solved it for me and wanted to share.

like image 45
devza Avatar answered Dec 06 '22 19:12

devza