Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Create Document with unique property in Mongoose

Create Document with unique property in Mongoose

Problem

I'm trying to save a document with a unique property across the collection.

So if someone tries to save a Kitten with {name: 'kitty'} and that name already exisits it fails and retries with {name: 'kitty1'} (then 'kitty2' etc).

I really can't figure out a good way to do this, any ideas?

Here's what I have so far (doesn't work).

var kittenSchema = new Schema ({
    name: {type: String, index: {unique: true}}
})

var Kitten = mongoose.model('Kitten', kittenSchema);

var kitten = new Kitten({
    name: 'kitty'
});

kitten.save(function(err, kitten){
    if (err){
        saveKitten(kitten, 1, function(err, kitten){
            if (err){
                console.log("Damn, no kitten");
            } else {
                console.log("New kitten " + kitten.name + "saved.");
            });
    } else {
        console.log("New kitten " + kitten.name + "saved.");
    }
}));

function saveKitten(kitten, count, callback){
    kitten.name = kitten.name + count;

    kitten.save(function(err, newKitten){
        if (err){
            if (count > 100){
                // Give up!
                callback(err, null);
            }

            saveKitten(kitten, count + 1, callback);
        } else {
            callback(null, newKitten);
        }
    }));
}
Problem courtesy of: Simon Hutton

Solution

After a pointer from NilsH I think I might try to pull back all possible name clashes and look for a new name locally.

Something like this:

var Kitten = mongoose.model('Kitten', kittenSchema);

var kitten = new Kitten({
    name: 'kitty'
});

Kitten.find({name: new RegExp('^'+ kitten.name +'*', "i")}, 'name').exec(function(err, docs){
    var tryName = name;
    var count = 0;

    while (True){
        if (_.indexOf(docs, tryName) != -1){
            break;
        } else {
            tryName = name + count;
        }
    }

    kitten.name = tryName;

    kitten.save(function(err, kitten){
        if (err){
            console.log("Damn, no kitten");
        } else {
            console.log("New kitten " + kitten.name + "saved.");
        }
    }));    
});

There's a possible race condition between finding the name and using it but I think I can live with that.

Solution courtesy of: Simon Hutton

Discussion

View additional discussion.



This post first appeared on Node.js Recipes, please read the originial post: here

Share the post

Create Document with unique property in Mongoose

×

Subscribe to Node.js Recipes

Get updates delivered right to your inbox!

Thank you for your subscription

×