我试图在MongoDB 3.0.4中推送到嵌套数组。这将说明问题 - 这是字符集中的文档,我想将image_4添加到Elmer的图像数组中:
{
"_id" : ObjectId("56084e91981824fc51693e72"),
"firstname" : "Elmer",
"lastname" : "Fudd",
"company" : "Warners",
"password" : "4567",
"galleries" : [
{
"gallery" : "1",
"images" : [
"image_1",
"image_2",
"image_3"
]
}
]
}
首先我尝试了:
db.characters.update({"firstname":"Elmer"},{$push {"galleries.$.images":"image_4"}})
并收到错误:
"writeError" : {
"code" : 16837,
"errmsg" : "The positional operator did not find the match needed from the query. Unexpanded update: galleries.$.images"
然后我在SO Update an item in an array that is in an array上看到了一个解决方案 并试过:
db.characters.update({"firstname":"Elmer"},{$push:{"galleries.0.images":"image_4"}})
工作得很好。我理解位置运算符$不能与嵌套数组一起使用,但为什么它的0替换有效,这个用法是0?我无法在Mongodb文档中找到它。
答案 0 :(得分:1)
在此用法中,0
会转换为
基于0的数组的第一个元素存储在第一个文档的
galleries
字段中,字段firstname
等于“Elmar”。
在这种情况下当然有效。但是,不保证每个查询都以相同的顺序返回数组。因此,如果您有两个图库,则可以将图库1作为第二个数组元素返回。
这里的问题是您的查询并没有真正反映您想要做的事情。你真正想做的是
在字段
firstname
等于“Elmar”的文档中,将“img_4”添加到galleries
中gallery
等于1的数组元素。
那么,我们将如何实现这一目标?基本上,您使用$
运算符是正确的。但是,您的查询不包含数组的匹配模式,这是必需的(查询引擎如何识别更新的确切数组元素)。所以你的查询需要稍微修改一下:
db.characters.update(
// The query part
{
// Nothing new here
"firstname": "Elmar",
// Now we want to identify the gallery:
// "Of all elements in the galleries array..."
"galleries": {
// "...find the element..."
"$elemMatch":{
// "...in which the field gallery equals 1."
"gallery": "1"
}
}
},
// Update part
{
// You want to use $addToSet instead of $push here
// since you don't want to have an image twice in a gallery
"$addToSet":{
// $ operator works now since we have identified the gallery
// in the query part
"galleries.$.images":"image_4"
}
}
)
请查看docs for the positional $
parameter了解详情。
旁注:截至撰写本文时,BSON文档的文档大小限制为16MB,因此您可能需要重新考虑您的模型。然而,这是一个不同的故事(并且如何在MongoDB中正确地模拟多对多关系,之前已被问过百万次)。