Mongodb:按元素分组并根据条件显示子文档计数并按日期对文档进行排序

Posted

技术标签:

【中文标题】Mongodb:按元素分组并根据条件显示子文档计数并按日期对文档进行排序【英文标题】:Mongodb: Group by element and show the sub-document count based on condition and sort the document by date 【发布时间】:2015-11-17 10:48:10 【问题描述】:

我收集的文件如下:


    "_id" : ObjectId("55d4410544c96d6f6578f893"),
    "executionProject" : "Project1",
    "suiteList" : [ 
        
            "suiteStatus" : "PASS",
        
    ],
    "runEndTime" : ISODate("2015-08-19T08:40:47.049Z"),
    "runStartTime" : ISODate("2015-08-19T08:40:37.621Z"),
    "runStatus" : "PASS",
    "__v" : 1



    "_id" : ObjectId("55d44eb4c0422e7b8bffe76b"),
    "executionProject" : "Project1",
    "suiteList" : [ 
        
            "suiteStatus" : "PASS",
        
    ],
    "runEndTime" : ISODate("2015-08-19T09:39:13.528Z"),
    "runStartTime" : ISODate("2015-08-19T09:39:00.406Z"),
    "runStatus" : "PASS",
    "__v" : 1



    "_id" : ObjectId("55d44f0bc0422e7b8bffe76f"),
    "executionProject" : "Project1",
    "suiteList" : [ 
        
            "suiteStatus" : "FAIL",
        
    ],
    "runEndTime" : ISODate("2015-08-19T09:46:31.108Z"),
    "runStartTime" : ISODate("2015-08-19T09:40:27.377Z"),
    "runStatus" : "PASS",
    "__v" : 1



    "_id" : ObjectId("55d463d0c0422e7b8bffe789"),
    "executionProject" : "Project2",
    "suiteList" : [ 
        
            "suiteStatus" : "FAIL"
        ,
        
            "suiteStatus" : "PASS"
        
    ],
    "runEndTime" : ISODate("2015-08-19T11:09:52.537Z"),
    "runStartTime" : ISODate("2015-08-19T11:09:04.539Z"),
    "runStatus" : "FAIL",
    "__v" : 1



    "_id" : ObjectId("55d464ebc0422e7b8bffe7c2"),
    "executionProject" : "Project3",
    "suiteList" : [ 
        
            "suiteStatus" : "FAIL"
        
    ],
    "runEndTime" : ISODate("2015-08-19T11:18:41.460Z"),
    "runStartTime" : ISODate("2015-08-19T11:13:47.268Z"),
    "runStatus" : "FAIL",
    "__v" : 10

我期望输出如下:

[
    
        "executionProject": "Project1",
        "suite-pass": 0,
        "suite-fail": 1,
        "runEndTime": ISODate("2015-08-19T09:46:31.108Z")
    ,
    
        "executionProject": "Project2",
        "suite-pass": 1,
        "suite-fail": 1,
        "runEndTime": ISODate("2015-08-19T11:09:52.537Z")
    ,
    
        "executionProject": "Project3",
        "suite-pass": 0,
        "suite-fail": 1,
        "runEndTime": ISODate("2015-08-19T11:18:41.460Z")
    ,
]

我想按项目分组并按 runEndTime 排序并显示 suiteList 的通过和失败计数。

我知道如何获得所有运行的套件通过和失败计数,但不确定如何分组和排序。请帮忙。

【问题讨论】:

【参考方案1】:

带有$cond 运算符的聚合框架似乎就是您所追求的:

  Model.aggregate([
     "$unwind": "$suiteList" ,
     "$group": 
      "_id": "$executionProject",
      "suite-pass":  
        "$sum": 
          "$cond": [
             "$eq": [ "$suiteList.suiteStatus", "PASS" ] ,
            1,
            0
          ]
        
      ,
      "suite-fail":  
        "$sum": 
          "$cond": [
             "$eq": [ "$suiteList.suiteStatus", "FAIL" ] ,
            1,
            0
          ]
        
      ,
      "runEndTime":  "$max": "$runEndTime" 
    ,
     "$sort":  "runEndTime": 1 
  ],function(err,result) 

  );

这有条件地测试“PASS”或“FAIL”的值,并将这些值返回到$group 下的$sum 累加器。以同样的方式获取每个分组文档的相关日期的 $max 值。

最后一件事就是到那个日期$sort


如果“suiteList”实际上最多只能包含一个“PASS”和一个“FAIL”,那么您甚至可以在数组上不使用$unwind 就可以逃脱:

  Model.aggregate(
    [
       "$group": 
        "_id": "$executionProject",
        "suite-pass": 
          "$sum": 
            "$cond": [
               "$anyElementTrue": 
                "$map": 
                  "input": "$suiteList",
                  "as": "suite",
                  "in": 
                    "$eq": [ "$$suite.suiteStatus", "PASS" ]
                  
                
              ,
              1,
              0
            ]
          
        ,
        "suite-fail": 
          "$sum": 
            "$cond": [
               "$anyElementTrue": 
                "$map": 
                  "input": "$suiteList",
                  "as": "suite",
                  "in": 
                    "$eq": [ "$$suite.suiteStatus", "FAIL" ]
                  
                
              ,
              1,
              0
            ]
          
        ,
        "runEndTime":  "$max": "$runEndTime" 
      ,
       "$sort":  "runEndTime": 1 
    ],
    function(err,results) 

    
  )

其中的$map$anyElementTrue 可以类似地测试数组中匹配的条件,它们应该被计算在内。因此,只要每个文档的“匹配数”无关紧要,就可以了。

如果您的数据确实满足这些条件,那么两者都会产生相同的结果:


    "_id" : "Project1",
    "suite-pass" : 2,
    "suite-fail" : 1,
    "runEndTime" : ISODate("2015-08-19T09:46:31.108Z")


    "_id" : "Project2",
    "suite-pass" : 1,
    "suite-fail" : 1,
    "runEndTime" : ISODate("2015-08-19T11:09:52.537Z")


    "_id" : "Project3",
    "suite-pass" : 0,
    "suite-fail" : 1,
    "runEndTime" : ISODate("2015-08-19T11:18:41.460Z")

要获得“最后一个”项目,只需先简单地 $sort 并将 $sum 累加器替换为 $last 累加器:

  Model.aggregate(
    [
       "$sort":  "runEndTime": 1  ,
       "$group": 
      "_id": "$executionProject",
        "suite-pass": 
          "$last": 
            "$cond": [
               "$anyElementTrue": 
                "$map": 
                  "input": "$suiteList",
                  "as": "suite",
                  "in": 
                    "$eq": [ "$$suite.suiteStatus", "PASS" ]
                  
                
              ,
              1,
              0
            ]
          
        ,
        "suite-fail": 
          "$last": 
            "$cond": [
               "$anyElementTrue": 
                "$map": 
                  "input": "$suiteList",
                  "as": "suite",
                  "in": 
                    "$eq": [ "$$suite.suiteStatus", "FAIL" ]
                  
                
              ,
              1,
              0
            ]
          
        ,
        "runEndTime":  "$last": "$runEndTime" 
      ,
       "$sort":  "runEndTime": 1  
    ],
    function(err,results) 

    
  );

产生:


    "_id" : "Project1",
    "suite-pass" : 0,
    "suite-fail" : 1,
    "runEndTime" : ISODate("2015-08-19T09:46:31.108Z")


    "_id" : "Project2",
    "suite-pass" : 1,
    "suite-fail" : 1,
    "runEndTime" : ISODate("2015-08-19T11:09:52.537Z")


    "_id" : "Project3",
    "suite-pass" : 0,
    "suite-fail" : 1,
    "runEndTime" : ISODate("2015-08-19T11:18:41.460Z")

【讨论】:

这太棒了。你介意回答我的问题吗?我如何只获得 executionProject 的独特价值?那个小组会这么神奇吗? @Vimal $group 有一个 _id,它是聚合的“分组键”。是的,它只返回分组字段的不同值。 太棒了。非常感谢您的回答。 我猜有问题。我期待 Project1 的 suite-pass 计数为 0,suite-fail 计数为 1,因为在 runEndTime 2015-08-19T09:40:27.377Z,只有一个套件,这也失败了。我不想要该项目的每次运行中所有套件的数量。目前正在取消标记答案,但如果我们找到任何其他更好的解决方案,很快就会再次标记。 @Vimal 为什么计数与您提供的数据列表不同?即使用我的眼睛进行目视检查也表明报告的计数是正确的。

以上是关于Mongodb:按元素分组并根据条件显示子文档计数并按日期对文档进行排序的主要内容,如果未能解决你的问题,请参考以下文章

按条件分组和计数

获取数组中每个索引的子文档元素计数并更新子文档键 - 数组中的子文档(IN MONGODB)

MongoDB聚合使用表达式运算符(函数)分组按条件计数统计案例一则

MongoDB聚合使用表达式运算符(函数)分组按条件计数统计案例一则

MongoDB计数按数组元素分组的数组中的匹配字符串

Mongodb Document : 有没有办法计算有条件的子文档?