我很难理解mongodb中重叠投影的工作原理。
这是一个快速举例说明我的难题(来自in-browser mongodb console的结果)。
首先,我创建并插入了一个简单的文档:
var doc = {
id:"universe",
systems: {
1: {
name:"milky_way",
coords:{x:1, y:1}
}
}
}
db.test.insert(doc);
// doc succesfully inserted
接下来,我尝试了一些奇怪的预测:
db.test.find({}, {"systems.1.coords":1, "systems.1":1});
//result
"_id" : ObjectId("537fd3541cdcaf1ba735becb"),
"systems" : {
"1" : {
"coords" : {
"y" : 1,
"x" : 1
}
}
}
}
我希望看到整个“系统1”,包括名称字段。但似乎“systems.1.coords”的更深层路径覆盖了较浅的路径,只是“system.1”?
我决定测试这个“更深层次的道路覆盖浅路径”理论:
db.test.find({}, {"systems.1.coords.x":1, "systems.1.coords":1});
//result
"_id" : ObjectId("537fd3541cdcaf1ba735becb"),
"systems" : {
"1" : {
"coords" : {
"y" : 1, // how'd this get here, but for the shallower projection?
"x" : 1
}
}
}
}
在这里,我的深层投影没有覆盖较浅的投影。
是什么给出的? mongodb如何处理重叠预测?我无法找到它的逻辑。
修改
我的困惑源于被视为“顶级”的道路。
这就像我预期的那样工作:.findOne({}, {"systems.1":1, "systems":1})
(即,尽管我从一个似乎是“较窄”的投影开始,但仍会返回一整套系统。)
但是,这不像我预期的那样工作:.findOne({}, {"systems.1.name":1, "systems.1":1})
(即只返回system.1的名称字段)。
简而言之,超过“一点”深度会导致在接受的答案中讨论覆盖。
答案 0 :(得分:1)
您不能使用。find()
进行此类投影,因为允许的一般投影是基本字段选择。您所谈论的是文档重塑,您可以使用$project
方法使用.aggregate()
运算符。
所以通过你最初的例子:
db.test.aggregate([
{ "$project": {
"coords": "$systems.1.coords",
"systems": 1
}}
])
这会给你这样的输出:
{
"_id" : ObjectId("537fe2127cb762d14e2a1007"),
"systems" : {
"1" : {
"name" : "milky_way",
"coords" : {
"x" : 1,
"y" : 1
}
}
},
"coords" : {
"x" : 1,
"y" : 1
}
}
请注意那里的不同字段命名,好像没有其他原因,来自.find()
的版本会导致您尝试的字段级别重叠路径(“系统”相同)选择,因此无法像在此处那样以两个字段投影。
以同样的方式,考虑如下声明:
db.test.aggregate([
{ "$project": {
"systems": {
"1": {
"coords": "$systems.1.coords"
}
},
"systems": 1
}}
])
所以这并没有告诉你它是无效的,只是投影中的一个结果是覆盖另一个,因为它们基本上处于顶层,它们都被称为“系统”。
这基本上是你在.find()
可用的投影方法尝试做这样的事情时最终得到的结果。因此,关键部分是您需要一个不同的字段名称,这就是聚合框架(虽然这里没有聚合)允许您这样做。