【问题标题】:Retrieving a count that matches specified criteria in a $group aggregation检索与 $group 聚合中的指定条件匹配的计数
【发布时间】:2017-02-06 18:31:29
【问题描述】:

因此,我希望将集合中的文档按特定字段分组,对于每个组的输出结果,我希望包括以下内容:

  1. 组中与特定查询匹配的所有文档计数(即满足某个表达式 { "$Property": "Value" } 的文档计数)
  2. 组中的文档总数
  3. (奖励,因为我怀疑这不容易实现)对应于 $min/$max 累加器的文档属性

我对用于在 mongo 中查询的语法非常陌生,不太了解它是如何工作的,但经过一些研究,我设法将其归结为以下查询(请注意,我目前为我的 mongo db 使用 3.0.12 版本,但我相信我们会在几个月后升级):

db.getCollection('myCollection').aggregate(
    [
        {
            $group: {
                _id: {
                    GroupID: "$GroupID", 
                    Status: "$Status"
                }, 
                total: { $sum: 1 }, 
                GroupName: { $first: "$GroupName" }, 
                EarliestCreatedDate: { $min: "$DateCreated" }, 
                LastModifiedDate: { $max: "$LastModifiedDate" }
            }
        }, 
        {
            $group: {
                _id: "$_id.GroupID", 
                Statuses: {
                    $push: {
                        Status: "$_id.Status", 
                        Count: "$total"
                    }
                }, 
                TotalCount: { $sum: "$total" }, 
                GroupName: { $first: "$GroupName" }, 
                EarliestCreatedDate: { $min: "$EarliestCreatedDate" }, 
                LastModifiedDate: { $max: "$LastModifiedDate" }
            }
        }
    ]
)

基本上我要检索的是特定状态值的计数,并将它们投影到一个最终结果文档中,如下所示:

{
    GroupName, 
    EarliestCreatedDate, 
    EarliestCreatedBy, 
    LastModifiedDate, 
    LastModifiedBy, 
    TotalCount,
    PendingCount, 
    ClosedCount
}

其中 PendingCount 和 ClosedCount 是每个组中具有 Pending/Closed 状态的文档总数。我怀疑我需要将 $project 与其他表达式一起使用来提取此值,但我对聚合管道的理解还不够好,无法弄清楚这一点。

此外,EarliestCreatedBy 和 LastModifiedBy 分别是创建/修改与 EarliestCreatedDate 和 LastModifiedDate 对应的文档的用户。正如我所提到的,我认为检索这些值会增加另一层复杂性,所以如果没有切实可行的解决方案,我愿意放弃这个要求。

非常感谢任何建议/提示。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    您可以尝试以下聚合阶段。

    $group

    计算每个GroupID 的所有必要计数TotalCountPendingCountClosedCount

    分别计算$min$maxEarliestCreatedDateLastModifiedDatepushCreatedByLastModifiedBy 的所有字段,以便稍后比较每个EarliestCreatedByLastModifiedBy 获取每个GroupID

    $project

    投影所有字段以进行响应

    $filterEarliestCreatedDate 值对CreatedByLastModifiedBy$map 中的数据匹配CreatedByEarliestCreatedBy$arrayElemAt 以将数组转换为对象。

    计算LastModifiedBy的类似步骤

    db.getCollection('myCollection').aggregate(
        [{
            $group: {
                _id: "$GroupID",
                TotalCount: {
                    $sum: 1
                },
                PendingCount: {
                    $sum: {
                        $cond: {
                            if: {
                                $eq: ["Status", "Pending"]
                            },
                            then: 1,
                            else: 0
                        }
                    }
                },
                ClosedCount: {
                    $sum: {
                        $cond: {
                            if: {
                                $eq: ["Status", "Closed "]
                            },
                            then: 1,
                            else: 0
                        }
                    }
                },
                GroupName: {
                    $first: "$GroupName"
                },
                EarliestCreatedDate: {
                    $min: "$DateCreated"
                },
                LastModifiedDate: {
                    $max: "$LastModifiedDate"
                },
                CreatedByLastModifiedBy: {
                    $push: {
                        CreatedBy: "$CreatedBy",
                        LastModifiedBy: "$LastModifiedBy",
                        DateCreated: "$DateCreated",
                        LastModifiedDate: "$LastModifiedDate"
                    }
                }
            }
        }, {
            $project: {
                _id: 0,
                GroupName: 1,
                EarliestCreatedDate: 1,
                EarliestCreatedBy: {
                    $arrayElemAt: [{
                        $map: {
                            input: {
                                $filter: {
                                    input: "$CreatedByLastModifiedBy",
                                    as: "CrBy",
                                    cond: {
                                        "$eq": ["$EarliestCreatedDate", "$$CrBy.DateCreated"]
                                    }
                                }
                            },
                            as: "EaCrBy",
                            in: {
                                "$$EaCrBy.CreatedBy"
                            }
                        }
                    }, 0]
                },
                LastModifiedDate: 1,
                LastModifiedBy: {
                    $arrayElemAt: [{
                        $map: {
                            input: {
                                $filter: {
                                    input: "$CreatedByLastModifiedBy",
                                    as: "MoBy",
                                    cond: {
                                        "$eq": ["$LastModifiedDate", "$$MoBy.LastModifiedDate"]
                                    }
                                }
                            },
                            as: "LaMoBy",
                            in: {
                                "$$LaMoBy.LastModifiedBy"
                            }
                        }
                    }, 0]
                },
                TotalCount: 1,
                PendingCount: 1,
                ClosedCount: 1
            }
        }]
    )
    

    版本

    $filter 在您的版本中也不可用。下面是等价的。

    比较逻辑是相同的,并为每个不匹配的条目创建一个数组,其值为falseLastModifiedBy,否则。

    下一步是使用$setDifference 将先前的数组值与数组[false] 进行比较,后者返回仅存在于第一个集合中的元素。

    LastModifiedBy: {
        $setDifference: [{
                $map: {
                    input: "$CreatedByLastModifiedBy",
                    as: "MoBy",
                    in: {
                        $cond: [{
                                $eq: ["$LastModifiedDate", "$$MoBy.LastModifiedDate"]
                            },
                            "$$MoBy.LastModifiedBy",
                            false
                        ]
                    }
                }
            },
            [false]
        ]
    }
    

    $project 阶段之后添加$unwind 阶段以更改为对象

    {$unwind:"$LastModifiedBy"}
    

    计算EarliestCreatedBy的类似步骤

    【讨论】:

    • $$ 在迭代期间访问中间变量的语法。例如 CrByEaCrBy 。在这里docs.mongodb.com/v3.2/reference/aggregation-variables
    • 非常感谢您的帮助。我通读了它,我认为它应该适合我的需要,但它似乎对我不起作用。我相信我的 mongo db 版本 3.0.12 不支持 $arrayElemAt 表达式(对不起,我应该在我的问题中指定)。你知道在这个版本中执行类似操作的方法吗?如果没有,我现在可以凑合;我相信我们希望在几个月内将我们的数据库升级到最新版本。
    • 不用担心。不客气。包括您的版本的更新。
    猜你喜欢
    • 1970-01-01
    • 2013-04-08
    • 2015-11-18
    • 2021-11-12
    • 2013-03-01
    • 2022-10-13
    • 2018-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多