这是我的示例文档:
{
a: 42,
map: {
x: { ... },
y: { ... },
z: { ... }
}
}
我正在寻找一种仅返回的方法:
{
a: 42,
map: {
y: { ... }
}
}
我只想指定 map 内要保留的字段。类似这样的事情...
db.myCollection.find({},
{
"map.y":1
}
)
...但是它也应该返回字段a
而不明确指定它。
我知道我还可以删除不需要的 map 条目:
db.myCollection.find({},
{
"map.x":0,
"map.z":0
}
)
但是这样,我需要在运行查询之前知道哪些 map 键可用。
有没有好的方法来处理这个问题?也许使用聚合框架?
谢谢:)
最佳答案
这基本上就是 MongoDB 以及许多其他数据库系统中投影或字段选择的工作原理。这里的概念基本上是“全有或全无”,因为如果您没有指定要返回的所有字段,则它们不会返回,当然默认情况下会返回您没有具体说明想要的内容的所有内容.
因此,当前数据仅返回 a
和 map.y
的正确形式是:
db.myCollection.find({}, { "a": 1, "map.y": 1 })
或者当然你可以告诉它你不想要什么:
db.myCollection.find({}, { "map.x": 0, "map.z": 0 })
但是您不能“混合”包含和排除,唯一的异常(exception)是 _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
的原因。运算符在测试字段不存在的级别人为地创建匹配。
但一般来说,投影要么全有,要么全无。指定您要返回的字段,否则它们将不存在。
关于mongodb - 通过投影从嵌套文档中删除除一个字段之外的所有字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25696731/