【问题标题】:MongoDB: count both matching documents and matching subdocuments, grouped by property of documentMongoDB:计算匹配的文档和匹配的子文档,按文档的属性分组
【发布时间】:2022-01-08 09:45:05
【问题描述】:

给定一个文档集合,每个文档都包含一个子文档数组(以及其他属性):

    {
        "prop1": False,
        "prop2": "unique_value",
        "subdocuments": [
            {
                "subprop1": 1,
                "subprop2": 10
            },
            {
                "subprop1": 30,
                "subprop2": 40
            },
            {
                "subprop1": 10,
                "subprop2": 1
            }
        ]
    }

还有一个涵盖文档和子文档的 $match 查询:

    {
        "prop1": False,
        "$or": [
            {"subdocuments.subprop1": {"$lt": 3}},
            {"subdocuments.subprop2": {"$lt": 5}}
        ]
    }

如何创建一个聚合查询,返回匹配子文档和匹配文档的数量,按根文档的特定属性分组

仅计算子文档总数和匹配文档很简单,但我也很难获得匹配子文档的正确计数。

理想情况下,我希望得到这样的结果(如果我们考虑示例文档,只有 subdoc 1 和 3 匹配 $or 条件):

    {
        "unique_value": {
            "documents": 1,
            "subdocuments": 2
        }
    }

在这种情况下,结果按“prop2”的值分组。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    您可以先使用$size$filter 获取匹配子文档的计数。然后执行$sum 获取documentCount 和subdocumentCount。

    db.collection.aggregate([
      {
        "$match": {
          "prop1": false,
          "$or": [
            {
              "subdocuments.subprop1": {
                "$lt": 3
              }
            },
            {
              "subdocuments.subprop2": {
                "$lt": 5
              }
            }
          ]
        }
      },
      {
        "$addFields": {
          "subdocumentCount": {
            $size: {
              "$filter": {
                "input": "$subdocuments",
                "as": "s",
                "cond": {
                  "$or": [
                    {
                      $lt: [
                        "$$s.subprop1",
                        3
                      ]
                    },
                    {
                      $lt: [
                        "$$s.subprop2",
                        5
                      ]
                    }
                  ]
                }
              }
            }
          }
        }
      },
      {
        $group: {
          _id: "$prop2",
          documentCount: {
            $sum: 1
          },
          subdocumentCount: {
            $sum: "$subdocumentCount"
          }
        }
      },
      {
        $project: {
          _id: 0,
          k: "$_id",
          v: {
            documentCount: "$documentCount",
            subdocumentCount: "$subdocumentCount"
          }
        }
      },
      {
        $group: {
          _id: null,
          docs: {
            $push: "$$ROOT"
          }
        }
      },
      {
        "$addFields": {
          "docs": {
            "$arrayToObject": "$docs"
          }
        }
      },
      {
        "$replaceRoot": {
          "newRoot": "$docs"
        }
      }
    ])
    

    这是Mongo playground 供您参考。

    【讨论】:

    • 此解决方案有效,但包含冗余匹配/过滤。当您只对文档计数感兴趣时,可以省略“$match”块。
    • @nulldroid 我想将过滤阶段放在更早的阶段会更好,因为它有助于减少中间结果的大小。
    • 我认为您误解了我的部分问题。最后,您按一个称为唯一值的字符串进行分组。我想按一个属性进行分组,在我的例子中是 prop2,在我的示例文档中,它的值是“unique_value”。考虑this playground,其中 prop2 在每个文档中具有不同的值。它们仍按“unique_value”与您的代码分组。
    • @IhateJS 这是一条有效的评论。我已经通过在您的示例中将 $group 键替换为唯一值(即 prop2)来更新答案。剩下的阶段只是修饰你的预期形式。
    猜你喜欢
    • 2011-09-26
    • 1970-01-01
    • 2017-05-18
    • 2021-02-25
    • 2015-02-10
    • 2015-10-31
    • 1970-01-01
    • 2013-10-21
    • 2019-09-03
    相关资源
    最近更新 更多