Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose unique index on subdocument

Let's say I have a simple schema:

var testSchema = new mongoose.Schema({
    map: { type: [ mongoose.Schema.Types.Mixed ], default: [] },
    ...possibly something else
});

Now let's ensure that pairs (_id, map._id) are unique.

testSchema.index({ _id: 1, 'map._id': 1 }, { unique: true });

Quick check using db.test.getIndexes() shows that it was created.

{
    "v" : 1,
    "unique" : true,
    "key" : {
        "_id" : 1,
        "map._id" : 1
    },
    "name" : "_id_1_map._id_1",
    "ns" : "test.test",
    "background" : true,
    "safe" : null
}

The problem is, this index is ignored and I can easily create multiple subdocuments with the same map._id. I can easily execute following query multiple times:

db.maps.update({ _id: ObjectId("some valid id") }, { $push: { map: { '_id': 'asd' } } });

and end up with following:

{
    "_id": ObjectId("some valid id"),
    "map": [
        {
            "_id": "asd" 
        },
        {
            "_id": "asd" 
        },
        {
            "_id": "asd" 
        }
    ]
}

What's going on here? Why can I push conflicting subdocuments?

like image 710
Sebastian Nowak Avatar asked Sep 18 '14 14:09

Sebastian Nowak


People also ask

How to add subdocument in mongoose?

Adding Subdocs to Arraysconst Parent = mongoose. model('Parent'); const parent = new Parent(); // create a comment parent. children. push({ name: 'Liesl' }); const subdoc = parent.

What does unique do in mongoose?

The unique option tells Mongoose that each document must have a unique value for a given path. For example, below is how you can tell Mongoose that a user's email must be unique. const mongoose = require('mongoose'); const userSchema = new mongoose.


2 Answers

Long story short: Mongo doesn't support unique indexes for subdocuments, although it allows creating them...

like image 99
Sebastian Nowak Avatar answered Sep 19 '22 03:09

Sebastian Nowak


This comes up in google so I thought I'd add an alternative to using an index to achieve unique key constraint like functionality in subdocuments, hope that's OK.

I'm not terribly familiar with Mongoose so it's just a mongo console update:

var foo = { _id: 'some value' }; //Your new subdoc here

db.yourCollection.update(
{ '_id': 'your query here', 'myArray._id': { '$ne': foo._id } },
{ '$push': { myArray: { foo } })

With documents looking like:

{
  _id: '...',
  myArray: [{_id:'your schema here'}, {...}, ...]
}

The key being that you ensure update will not return a document to update (i.e. the find part) if your subdocument key already exists.

like image 36
phuhgh Avatar answered Sep 21 '22 03:09

phuhgh