【问题标题】:Can I easily return all of the fields of a subdocument as fields in the top level document using the aggregation framework?我可以使用聚合框架轻松地将子文档的所有字段作为顶级文档中的字段返回吗?
【发布时间】:2026-01-29 21:15:01
【问题描述】:

我有一个类似下面的文档,我想从中返回当前*字段的子字段作为结果数组的每个文档中的*字段:

{ 
  field1: {
    subfield1: {},
    subfield2: [],
    subfield3: 44,
    subfield5: xyz
  },
  field2: {
    othercontent: {}
  }
}

我希望我的聚合查询的结果返回以下内容(field1 的内容作为*文档):

{
  subfield1: {},
  subfield2: [],
  subfield3: 44,
  subfield5: xyz
}

这可以通过$project 和聚合框架来完成,而无需将每个子字段都定义为*字段返回吗?

【问题讨论】:

标签: mongodb mongodb-query


【解决方案1】:

从 3.4 开始可以使用$replaceRoot 聚合运算符:

db.getCollection('sample').aggregate([
    {
        $replaceRoot: {newRoot: "$field1"}
    }
])

按预期提供输出:

{
    "subfield" : {},
    "subfield2" : [],
    "subfield3" : 44,
    "subfield5" : "xyz"
}

【讨论】:

    【解决方案2】:

    通常很难让 MongoDB 处理模棱两可或参数化的 json 键。我遇到了similar issue,最好的解决方案是修改架构,使子文档的成员成为数组中的元素。

    但是,我认为这会让你接近你想要的(所有代码都应该直接在 Mongo shell 中运行)。假设您有以下文件:

    db.collection.insert({
      "_id": "doc1",
      "field1": {
               "subfield1": {"key1": "value1"},
               "subfield2": ["a", "b", "c"],
               "subfield3": 1,
               "subfield4": "a"
             },
      "field2": "other content"
    })
    
    db.collection.insert({ 
      "_id": "doc2",
      "field1": {
               "subfield1": {"key2": "value2"},
               "subfield2": [1, 2, 3],
               "subfield3": 2,
               "subfield4": "b"
    
             },
      "field2": "yet more content"
    })
    

    然后您可以运行一个聚合命令来提升field1 的内容,同时忽略文档的其余部分:

    db.collection.aggregate({
    "$group":{
        "_id": "$_id",
        "value": {"$push": "$field1"}
    }})
    

    这使得所有subfield* 键成为对象的*字段,并且该对象是数组中的唯一元素。这很笨拙,但可行:

    "result" : [
            {
                    "_id" : "doc2",
                    "value" : [
                            {
                                    "subfield1" : {"key2" : "value2"},
                                    "subfield2" : [1, 2, 3],
                                    "subfield3" : 2,
                                    "subfield4" : "b"
                            }
                    ]
            },
            {
                    "_id" : "doc1",
                    "value" : [
                            {
                                    "subfield1" : {"key1" : "value1"},
                                    "subfield2" : ["a","b","c"],
                                    "subfield3" : 1,
                                    "subfield4" : "a"
                            }
                    ]
            }
    ],
    "ok" : 1
    

    【讨论】:

    • 这不符合题主的要求。输出文档的形状不同。
    【解决方案3】:

    Mongo 4.2 开始,$replaceWith 聚合运算符可用于将文档替换为另一个文档(在我们的示例中为子文档),作为 $replaceRoot 的语法糖:

    // { field1: { a: 1, b: 2, c: 3 }, field2: { d: 4, e: 5 } }
    // { field1: { a: 6, b: 7 }, field2: { d: 8 } }
    db.collection.aggregate({ $replaceWith: "$field1" })
    // { a: 1, b: 2, c: 3 }
    // { a: 6, b: 7 }
    

    【讨论】:

      最近更新 更多