【问题标题】:$group inner array values without $unwind没有 $unwind 的 $group 内部数组值
【发布时间】:2019-05-15 01:45:16
【问题描述】:

我想按指定字段的相同值对数组中的对象进行分组并产生一个计数。

我有以下 mongodb 文档(不相关的字段不存在)。

{
  arrayField: [ 
    { fieldA: value1, ...otherFields }, 
    { fieldA: value2, ...otherFields },
    { fieldA: value2, ...otherFields } 
  ],
  ...otherFields
}

以下是我想要的。

{
  arrayField: [ 
    { fieldA: value1, ...otherFields }, 
    { fieldA: value2, ...otherFields },
    { fieldA: value2, ...otherFields } 
  ],
  newArrayField: [ 
    { fieldA: value1, count: 1 }, 
    { fieldA: value2, count: 2 },
  ],
  ...otherFields
}

这里我按 fieldA 对嵌入文档进行了分组。

我知道如何通过以下方式进行放松和 2 个小组阶段。 (无关的阶段被省略)

具体例子

// document structure
{
  _id: ObjectId(...),
  type: "test",
  results: [ 
    { choice: "a" }, 
    { choice: "b" },
    { choice: "a" } 
  ]
}
db.test.aggregate([
{ $match: {} },
{
  $unwind: {
    path: "$results",
    preserveNullAndEmptyArrays: true
  }
},
{
  $group: {
    _id: {
      _id: "$_id",
      type: "$type",
      choice: "$results.choice",
    },
    count: { $sum: 1 }
  }
},
{
  $group: {
    _id: {
      _id: "$_id._id",
      type: "$_id.type",
      result: "$results.choice",
    },
    groupedResults: { $push: { count: "$count", choice: "$_id.choice" } }
  }
}
])

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    您可以在下面使用aggregation

    db.test.aggregate([
      { "$addFields": {
        "newArrayField": {
          "$map": {
            "input": { "$setUnion": ["$arrayField.fieldA"] },
            "as": "m",
            "in": {
              "fieldA": "$$m",
              "count": {
                "$size": {
                  "$filter": {
                    "input": "$arrayField",
                    "as": "d",
                    "cond": { "$eq": ["$$d.fieldA", "$$m"] }
                  }
                }
              }
            }
          }
        }
      }}
    ])
    

    【讨论】:

      【解决方案2】:

      下面添加了一个新的数组字段,它的生成方式是:

      1. 使用$setUnion获取唯一的数组项集,内部$map 仅提取 choice 字段
      2. 在唯一的项目集上使用$map, 在原始数组上使用内部$reduce,对所有项目求和 choice 匹配

      管道:

      db.test.aggregate([{
        $addFields: {
          newArrayField: {
            $map: {
              input: {
                $setUnion: [{
                    $map: {
                      input: "$results",
                      in: { choice: "$$this.choice" }
                    }
                  }
                ]
              },
              as: "i",
              in: {
                choice: '$$i.choice',
                count: {
                  $reduce: {
                    input: "$results",
                    initialValue: 0,
                    in: { 
                      $sum: ["$$value", { $cond: [ { $eq: [ "$$this.choice", "$$i.choice" ] }, 1, 0 ] }]
                    }
                  }
                }
              }
            }
          }
        }
      }])
      

      $reduce 将迭代results 数组n 次,其中n 是选择的唯一值的数量,因此性能将取决于此。

      【讨论】:

        猜你喜欢
        • 2019-10-02
        • 2019-03-21
        • 2019-09-03
        • 2017-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多