如何优化聚合查询以根据不同的键进行分组?

How to optimise aggregation query to group based on different keys?

我的 mongoDB 文档如下所示:

[
  {
    "fields": {
      "field_1": {
        "name": "f1",
        "first": {
          "check": true
        }
      },
      "field_2": {
        "name": "f2",
        "second": {
          "check": true
        }
      },
      "field_3": {},
      "field_4": {
        "name": "f4",
        "second": {
          "check": true
        }
      }
    }
  },
  {
    "fields": {
      "field_1": {
        "name": "f1",
        "second": {
          "check": false
        }
      },
      "field_2": {
        "name": "f2",
        "second": {
          "check": true
        },
        "first": {
          "check": true
        }
      },
      "field_3": {
        "name": "f3",
        "second": {
          "check": true
        }
      }
    }
  }
]

预期输出:

  1. 创建父组 f1(fields.field1.name) 和 f2(fields.field2.name)

  2. 他们每个人都有两个子组,这些子组根据以下条件显示指标 各自父组:

    1. first_group: first.check=true
    2. 的文档数
    3. second_group:first.check 不存在且 second.check=true
    4. 的文档数

结果:

[
  {
    "data": [
      {
        "_id": "f1",
        "values": [
          {     
            "second_group": 0,
            "first_group": 1
          }
        ]
      },
      {
        "_id": "f2",
        "values": [
          {
            "second_group": 1,
            "first_group": 1
          }
        ]
      }
    ]
  }
]

我已经使用 $facet 生成了查询,但我不满意,因为我必须在每个父组中重复我的子级分组逻辑(我在 $facet 中有 4 个数组)

My Query in Mongo Playground attached here

请告诉我如何删除重复查询。 有没有其他方法可以实现这个用例?

谢谢!

发布应该适用于给定条件和预期的聚合查询 O/p:

db.collection.aggregate([
  {
    $unwind: "$fields",
  },
  {
    $project: {
      data: {
        $objectToArray: "$fields",
      },
    },
  },
  {
    $unwind: "$data",
  },
  {
    $match: {
      "data.v.first.check": true,
    },
  },
  {
    $group: {
      _id: "$data.v.name",
      values: {
        $push: {
          first_group: {
            $sum: {
              $cond: [
                {
                  $eq: ["$data.v.first.check", true],
                },
                1,
                0,
              ],
            },
          },
          second_group: {
            $sum: {
              $cond: [
                {
                  $eq: ["$data.v.second.check", true],
                },
                1,
                0,
              ],
            },
          },
        },
      },
    },
  },
]);

Play link

备选方案:

我们标准化 fields 属性并使用 $convert operator to Integer with this behavior.

计算 first_groupsecond_group
Input Type  Behavior
---------------------
Boolean     Returns 0 for false.
            Returns 1 for true.

db.collection.aggregate([
  {
    $project: {
      fields: {
        $map: {
          input: [
            "$fields.field_1",
            "$fields.field_2"
          ],
          as: "field",
          in: {
            _id: "$$field.name",
            first_group: {
              $convert: {
                input: "$$field.first.check",
                to: 16,
                onNull: 0
              }
            },
            second_group: {
              $convert: {
                input: {
                  $and: [
                    {
                      $eq: [
                        {
                          $type: "$$field.first.check"
                        },
                        "missing"
                      ]
                    },
                    "$$field.second.check"
                  ]
                },
                to: 16,
                onNull: 0
              }
            }
          }
        }
      }
    }
  },
  {
    $unwind: "$fields"
  },
  {
    $group: {
      _id: "$fields._id",
      first_group: {
        $sum: "$fields.first_group"
      },
      second_group: {
        $sum: "$fields.second_group"
      }
    }
  },
  {
    $group: {
      _id: null,
      data: {
        $push: {
          _id: "$_id",
          values: [
            {
              first_group: "$first_group",
              second_group: "$second_group"
            }
          ]
        }
      }
    }
  }
])

MongoPlayground