【问题标题】:Remove all but one field from a nested document via projection通过投影从嵌套文档中删除除一个字段外的所有字段
【发布时间】:2014-09-06 04:20:09
【问题描述】:

这是我的示例文档:

{
  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
  }
)

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

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

谢谢:)

【问题讨论】:

    标签: mongodb mongodb-query projection aggregation-framework


    【解决方案1】:

    这基本上是 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 也遵循一般投影规则),否则这些字段不会出现在结果中。

    事实上,我的员工常犯的一个错误是使用这些阶段之一“删除”字段,然后尝试引用后来删除的字段。它是一个“管道”,就像 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 运算符人为地在测试字段不存在的级别。

    但一般来说,投影是全有或全无。指定要返回的字段,否则它们将不存在。

    【讨论】:

    • 太糟糕了,因为数组不能很好地映射到我的 Java 类。但我当然可以解决这个问题。 ... 现在我有第二个小问题:当使用typecontent 的数组方法时,是否可以使用与$elemMatch 相反的运算符进行投影? IE。 (伪代码)map: {$elemMatch: {type: NOT "y"}} : 0,因此它将删除数组中的所有内容,其中type != "y"
    • @BenjaminM 正如我所解释的,没有其他方法可以让另一个字段(例如“a”)出现,而无需明确说明您也希望它返回。 $redact 是一种特殊情况,它从文档中“删除”元素,在这种情况下,“类型”字段不匹配。所以没有其他方式意味着没有其他方式。
    • 感谢您的精彩解释!!! 我得考虑一下。我可以只为map 使用第二个集合,然后我可以轻松地使用标准投影。
    猜你喜欢
    • 2019-05-31
    • 1970-01-01
    • 2013-08-26
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多