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?
Long story short: Mongo doesn't support unique indexes for subdocuments, although it allows creating them...
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.
First objectId length in mongodb must be 24. Then you can turn off _id, and rename _id as id or others,and try $addToSet. Good luck.
CoffeeScript example:
FromSchema = new Schema(
source: { type: String, trim: true }
version: String
{ _id: false }//to trun off _id
)
VisitorSchema = new Schema(
id: { type: String, unique: true, trim: true }
uids: [ { type: Number, unique: true} ]
from: [ FromSchema ]
)
//to update
Visitor.findOneAndUpdate(
{ id: idfa }
{ $addToSet: { uids: uid, from: { source: source, version: version } } }
{ upsert: true }
(err, visitor) ->
//do stuff