我们说我有一个简单的架构:
var testSchema = new mongoose.Schema({
map: { type: [ mongoose.Schema.Types.Mixed ], default: [] },
...possibly something else
});
现在让我们确保配对(_id
,map._id
)是唯一的。
testSchema.index({ _id: 1, 'map._id': 1 }, { unique: true });
使用db.test.getIndexes()
快速检查表明它已创建。
{
"v" : 1,
"unique" : true,
"key" : {
"_id" : 1,
"map._id" : 1
},
"name" : "_id_1_map._id_1",
"ns" : "test.test",
"background" : true,
"safe" : null
}
问题是,这个索引被忽略了,我可以轻松创建多个具有相同map._id
的子文档。我可以轻松地多次执行以下查询:
db.maps.update({ _id: ObjectId("some valid id") }, { $push: { map: { '_id': 'asd' } } });
并最终得到以下内容:
{
"_id": ObjectId("some valid id"),
"map": [
{
"_id": "asd"
},
{
"_id": "asd"
},
{
"_id": "asd"
}
]
}
这里发生了什么?为什么我可以推送冲突的子文档?
答案 0 :(得分:19)
长话短说:Mongo不支持子文档的唯一索引,尽管它允许创建它们......
答案 1 :(得分:11)
这出现在谷歌中,所以我想我会添加一个替代方法来使用索引来实现像子文档中的功能一样的唯一键约束,希望没问题。
我对Mongoose并不十分熟悉,所以它只是一个mongo控制台更新:
var foo = { _id: 'some value' }; //Your new subdoc here
db.yourCollection.update(
{ '_id': 'your query here', 'myArray._id': { '$ne': foo._id } },
{ '$push': { myArray: { foo } })
文档看起来像:
{
_id: '...',
myArray: [{_id:'your schema here'}, {...}, ...]
}
如果你的子文档密钥已经存在,那么确保更新的关键不会返回要更新的文档(即查找部分)。
答案 2 :(得分:-3)
mongodb中的第一个objectId长度必须为24.然后您可以关闭_id,并将_id重命名为id或其他,并尝试$addToSet。祝你好运。
CoffeeScript示例:
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