没有$ unwind的$ group内部数组值

时间:2019-04-17 11:05:58

标签: mongodb mongodb-query aggregation-framework

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

我有以下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" } }
  }
}
])

2 个答案:

答案 0 :(得分:2)

您可以在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"] }
              }
            }
          }
        }
      }
    }
  }}
])

答案 1 :(得分:1)

下面添加了一个新的数组字段,该字段由以下内容生成:

  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是选择的唯一值的数量,因此性能将取决于此。 / p>