检索与 $group 聚合中的指定条件匹配的计数

Posted

技术标签:

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

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

    组中与特定查询匹配的所有文档计数(即满足某个表达式 "$Property": "Value" 的文档计数) 组中的文档总数 (奖励,因为我怀疑这不容易实现)对应于 $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 对应的文档的用户。正如我所提到的,我认为检索这些值会增加另一层复杂性,所以如果没有切实可行的解决方案,我愿意放弃这个要求。

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

【问题讨论】:

【参考方案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 表达式(对不起,我应该在我的问题中指定)。你知道在这个版本中执行类似操作的方法吗?如果没有,我现在可以凑合;我相信我们希望在几个月内将我们的数据库升级到最新版本。 不用担心。不客气。包括您的版本的更新。

以上是关于检索与 $group 聚合中的指定条件匹配的计数的主要内容,如果未能解决你的问题,请参考以下文章

mongo中的高级查询之聚合操作(distinct,count,group)与数据去重

聚合数组中的对象与多个条件匹配的文档

SQL中只要用到聚合函数就一定要用到group by 吗?

选择列表中的列无效,因为该列没有包含在聚合函数或 GROUP BY 子句中

具有特定条件计数的 Mongodb 聚合并按输出投影的日期范围过滤不能按预期工作

AWK:使用两个匹配条件的文件和计数相等的唯一标识符