了解重叠的mongodb投影

时间:2014-05-23 23:17:39

标签: mongodb projection aggregation-framework

我很难理解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的名称字段)。

简而言之,超过“一点”深度会导致在接受的答案中讨论覆盖。

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()可用的投影方法尝试做这样的事情时最终得到的结果。因此,关键部分是您需要一个不同的字段名称,这就是聚合框架(虽然这里没有聚合)允许您这样做。