【问题标题】:Mongodb: Group by element and show the sub-document count based on condition and sort the document by dateMongodb:按元素分组并根据条件显示子文档计数并按日期对文档进行排序
【发布时间】: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 的通过和失败计数。

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

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query aggregation-framework


    【解决方案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 为什么计数与您提供的数据列表不同?即使用我的眼睛进行目视检查也表明报告的计数是正确的。
    猜你喜欢
    • 2016-04-10
    • 2015-05-07
    • 2015-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多