【问题标题】:Reference document fields in collection of embedded documents in aggregation pipeline在聚合管道中的嵌入文档集合中引用文档字段
【发布时间】:2020-09-23 07:46:46
【问题描述】:

我正在尝试在管道阶段合并位于嵌入文档集合中的两个数组字段。但我不知道如何引用嵌入文档的两个“internal”数组。

集合

[{
    name: "first",
    docs: [
        { a1: ["a", "b"], a2: ["c"] },
        { a1: ["d", "e"], a2: ["f"] }
    ]
},
{
    name: "second",
    docs: [
        { a1: [1, 2], a2: [3] },
        { a1: [4, 5], a2: [6] }
    ]
}]

预期结果

[{
    name: "first",
    docs: [
        { merged: ["a", "b", "c"] },
        { merged: ["d", "e", "f"] }
    ]
},
{
    name: "second",
    docs: [
        { merged: [1, 2, 3] },
        { merged: [4, 5, 6] }
    ]
}]

方法

到目前为止,我尝试的总体方法是: (带有 2 个用于测试目的的硬编码数组)

db.getCollection("collection").aggregate([{
    $set: {
         "docs.merged": {
             $concatArrays: [["hello"], ["world"]]
         }
    }
}])

产生预期结果:

[{
    name : "first",
    docs : [
        {
            a1 : ["a", "b"],
            a2 : ["c"],
            merged : ["hello", "world"] // <- OK
        },
        {
            a1 : ["d", "e"],
            a2 : ["f"],
            merged : ["hello", "world"] // <- OK
        }
    ]
},{
    name : "second",
    docs : [
        {
            a1 : [1.0, 2.0],
            a2 : [3.0],
            merged : ["hello", "world"] // <- OK
        },
        {
            a1 : [4.0, 5.0],
            a2 : [6.0],
            merged : ["hello", "world"] // <- OK
        }
    ]
}]

但我很难掌握如何引用 当前 嵌入文档中的字段:

// Using the "$" reference causes following error:
// Invalid $set :: caused by :: FieldPath field names may not start with '$'.
{
    $set: {
         "docs.merged": { $concatArrays: ["$docs.$.a1", "$docs.$.a2"] }
    }
}

// $$this is only available with a MAP operator
{
    $set: {
         "docs.merged": { $concatArrays: ["$$this.a1", "$$this.a2"] }
    }
}

注意事项

我不能使用update 查询,因为不得更改原始文档。所以这必须aggregate 管道中实现。

此时我尽量避免使用unwind 操作,因为这会对性能产生重大影响。 actual 文档的根目录包含相当多的(可变)字段;在unwind 之后制作一个group 阶段相当复杂。 (为了便于阅读,该示例已大大简化)

我正在使用 MongoDB v4.4

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    我认为这样就可以了,如果有什么我遗漏的,请告诉我:

    db.collection.aggregate([{
       $project: {
          _id: 0,
          "name": 1,
          "docs": {
             $function: {
                body: function(docs) {
                  docs.forEach(function(doc) {
                     var merged = [];
                     Object.keys(doc).forEach(function(k) {
                        merged = merged.concat(doc[k]);
                        delete doc[k];
                     });
                     doc.merged = merged;
                  });
                  return docs;
                },
                args: [ "$docs" ],
                lang: "js"
             }
          }
       }
    }])
    

    【讨论】:

    • 我希望它可以通过内置功能解决。但是$function 运算符完美地解决了这个问题,性能影响可接受。谢谢!
    【解决方案2】:

    您可以执行以下操作。

    1. 首先 $unwind 将 docs 数组展平。
    2. 由于 a1 和 a2 是动态的,我们将其制成数组。 (如果我们使用这个,多个动态键可以构建您的输出)。
    3. 然后$reduce 将数据添加到数组中。
    4. 并将其重新组合以获得所需的输出。

    聚合脚本是

    [
      {
        "$unwind": "$docs"
      },
      {
        $project: {
          name: 1,
          data: {
            $objectToArray: "$docs"
          }
        }
      },
      {
        $project: {
          name: 1,
          data: {
            $reduce: {
              input: "$data",
              initialValue: [],
              in: {
                $concatArrays: [
                  "$$this.v",
                  "$$value"
                ]
              }
            }
          }
        }
      },
      {
        $group: {
          _id: "$_id",
          name: {
            $first: "$name"
          },
          docs: {
            $push: {
              merged: "$data"
            }
          }
        }
      }
    ]
    

    工作Mongo playground

    【讨论】:

    • 我尽量避免unwind,因为这会迫使我重新组合文档。这更复杂,因为我的实际文档在其根目录中包含许多(变量)属性。问题更多是关于如何引用嵌入文档中的字段。
    • 我也尝试过不同的方式,但我觉得无论如何你需要使用组。但是您可以将其按$$ROOT 分组并替换为数据。但我急切地等待不使用 unwind 和 group 的人回复
    • 我不确定,但也许 $function 可以帮助解决这个问题 - 因为您使用的是 MongoDB v4.4+。
    猜你喜欢
    • 2019-10-05
    • 2015-05-01
    • 2018-03-28
    • 2021-10-24
    • 2018-07-14
    • 1970-01-01
    • 2013-09-18
    • 2019-05-20
    • 1970-01-01
    相关资源
    最近更新 更多