通过投影从嵌套文档中删除除一个字段之外的所有字段

时间:2014-09-06 04:20:09

标签: mongodb mongodb-query projection aggregation-framework

这是我的示例文档:

{
  a: 42,
  map: {
    x: { ... },
    y: { ... },
    z: { ... }
  }
}

我正在寻找一种只返回的方式:

{
  a: 42,
  map: {
    y: { ... }
  }
}

我只想在地图中指定字段以保持。像那样......

db.myCollection.find({},
  {
    "map.y":1
  }
)

... 但是它还应该返回字段a而不明确指定它。

我知道我也可以删除不需要的地图条目:

db.myCollection.find({},
  {
    "map.x":0,
    "map.z":0
  }
)

但是这样,在运行查询之前我需要知道哪些地图键可用。

有没有一个很好的方法来处理这个?也许使用聚合框架?

谢谢:)

1 个答案:

答案 0 :(得分:2)

这基本上是在MongoDB以及许多其他数据库系统中投影或字段选择的工作原理。这里的概念基本上是"全部或全部",因为如果你没有指定你想要返回的所有字段,它们就不会被返回,当然默认是返回你所不知道的所有字段。特别说出你想要的东西。

因此,返回amap.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也遵循一般投影规则),或者结果中不存在这些字段。

事实上,一个常见的错误使我的员工正在“删除”#34;具有其中一个阶段的字段,然后尝试引用稍后删除的字段。它是一个"管道",就像Unix管道|一样,流向下一阶段的唯一内容就是你指定的内容:

唯一的"真实"如果只是匹配字段而不指定其他字段,则可以通过更改结构来实现" map"作为一个数组,然后使用MongoDB 2.6及更高版本的$redact管道阶段。虽然有点做作:

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运算符在测试字段不存在的级别上人为地创建匹配的原因。

但一般来说,投射是全有或全无的。指定要返回的字段,或者它们不在那里。