这基本上是 MongoDB 以及许多其他数据库系统中投影或字段选择的工作方式。这里的概念基本上是“全有或全无”,因为如果您不指定要返回的所有字段,则不会返回它们,当然默认是返回您没有具体说明想要什么的所有内容.
因此,仅返回 a 和 map.y 的当前数据的正确形式是:
db.myCollection.find({}, { "a": 1, "map.y": 1 })
或者你当然可以告诉它你不想要什么:
db.myCollection.find({}, { "map.x": 0, "map.z": 0 })
但是您不能“混合”包含和排除,唯一的例外是您不希望在结果中出现的 _id 字段,可能会考虑“覆盖索引”查询,但通常您需要主键:
db.myCollection.find({}, { "_id": 0, "a": 1, "map.y": 1 })
至于聚合框架,它和$project 和$group 等运算符是一样的,特别和同样残酷。在这两种情况下,您都需要准确指定要返回的内容( $project 也遵循一般投影规则),否则这些字段不会出现在结果中。
事实上,我的员工常犯的一个错误是使用这些阶段之一“删除”字段,然后尝试引用后来删除的字段。它是一个“管道”,就像 Unix 管道 | 一样,唯一流向下一阶段的内容就是您指定的内容:
唯一“真正”的情况是,您可以排除除匹配字段之外的所有字段而不指定其他字段,即更改结构以将“map”实现为数组,然后使用$redact 管道阶段,可从 MongoDB 2.6 和向上。虽然有点做作:
db.test.insert({
"a": 42,
"map": [
{ "type": "x", "content": {} },
{ "type": "y", "content": {} },
{ "type": "z", "content": {} }
]
})
以及对这样结构的数据的聚合操作:
db.test.aggregate([
{ "$redact": {
"$cond": [
{ "$eq": [
{ "$ifNull": [ "$type", "y" ] },
"y"
]},
"$$DESCEND",
"$$PRUNE"
]
}}
])
所以我们只要求匹配“type”等于“y”的元素,但这里通常需要小心,因为 $redact 正在递归处理,这就是$ifNull 运算符人为地在测试字段不存在的级别。
但一般来说,投影是全有或全无。指定要返回的字段,否则它们将不存在。