Mongodb $ cond在聚合框架中

时间:2013-01-11 22:16:01

标签: mongodb

我有一个包含如下文档的集合: {

ipAddr: '1.2.3.4',
"results" : [
             {
                     "Test" : "Sight",
                     "Score" : "FAIL",
                     "Reason" : "S1002"
             },
             {
                     "Test" : "Speed",
                     "Score" : "FAIL",
                     "Reason" : "85"
             },
             {
                     "Test" : "Sound",
                     "Score" : "FAIL",
                     "Reason" : "A1001"
             }
     ],
     "finalGrade" : "FAILED"

}

这是我正在尝试编写的聚合查询,我想要做的事情(参见注释掉的部分),就是创建一个分组字段,每个ipAddr, '原因/错误'代码,但仅当原因代码以特定字母开头,并且只添加一次代码时,我尝试了以下内容:

 db.aggregate([
   {$group: 
        {  _id: "$ipAddr", 
         attempts: {$sum:1}, 
         results: {$push: "$finalGrade"},    
        // errorCodes: {$addToSet: {$cond: ["$results.Reason": /[A|B|S|N.*/, "$results.Reason", ""]}},                                                              
        finalResult: {$last: "$finalGrade"} } 
   }
]);

一切正常,不包括注释掉的'errorCodes'行。我试图创建的逻辑是: “添加errorCodes设置结果的值。因为它以A,B,S或N开头,否则没有任何东西可以添加”。

对于上面的记录,错误代码集应该包含:
  ... errorCodes:[S1002,A1001],   ...

2 个答案:

答案 0 :(得分:5)

$group无法使用条件表达式,这就是该行不起作用的原因。 $project是您可以根据$cond表达式(以及其他内容)转换原始文档的阶段。

$group之前,您需要在汇总管道中执行两个步骤 - 首先需要$unwind结果数组,然后您需要$match来过滤掉您不想要的结果不关心。

这样做的好处很简单,就是只丢弃你不关心的错误代码的结果,但听起来你想要计算包括所有错误代码在内的失败总数,但只是添加特定错误代码到输出数组?没有直接的方法可以做到这一点,你必须在管道中进行两次$group $unwind次传递。

类似的东西会这样做:

db.aggregate([
   {$unwind : "$results"},
   {$group:
        { _id: "$ipAddr",
          attempts: {$sum:1},
          results: {$push : "$results"},
          finalGrade: {$last : "$finalGrade" } 
        } 
   },
   {$unwind: "$results"},
   {$match: {"results.Reason":/yourMatchExpression/} },
   {$group: 
        {  _id: "$ipAddr", 
         attempts: {$last:"$attempts"},    
         errorCodes: {$addToSet: "$results.Reason"},                                                              
        finalResult: {$last: "$finalGrade"}
   }
]);

如果您只想计算具有匹配错误代码的尝试,那么您可以使用单个$group来执行此操作 - 您需要执行$unwind$match和{{1 }}。您可以使用带有$group的$ project,但随后您的errorCodes数组将包含一个空字符串条目以及所有正确的错误代码。

答案 1 :(得分:0)

从Mongo 2.4开始,$ regex可用于模式匹配,但不能用作返回布尔值的表达式,这是$ cond所需要的

然后,您可以使用$ match运算符来使用$ regex关键字:

http://mongotry.herokuapp.com/#?bookmarkId=52fb39e207fc4c02006fcfed

[
{
    "$unwind": "$results"
},
{
    "$match": {
        "results.Reason": {
            "$regex": "[SA].*"
        }
    }
},
{
    "$group": {
        "_id": "$ipAddr",
        "attempts": {
            "$sum": 1
        },
        "results": {
            "$push": "$finalGrade"
        },
        "undefined": {
            "$last": "$finalGrade"
        },
        "errorCodes": {
            "$addToSet": "$results.Reason"
        }
    }
}
]

或者您可以使用$ substr,因为您的模式匹配非常简单 http://mongotry.herokuapp.com/index.html#?bookmarkId=52fb47bc7f295802001baa38

[
{
    "$unwind": "$results"
},
{
    "$group": {
        "_id": "$ipAddr",
        "errorCodes": {
            "$addToSet": {
                "$cond": [
                    {
                        "$or": [
                            {
                                "$eq": [
                                    {
                                        "$substr": [
                                            "$results.Reason",
                                            0,
                                            1
                                        ]
                                    },
                                    "A"
                                ]
                            },
                            {
                                "$eq": [
                                    {
                                        "$substr": [
                                            "$results.Reason",
                                            0,
                                            1
                                        ]
                                    },
                                    "S"
                                ]
                            }
                        ]
                    },
                    "$results.Reason",
                    "null"
                ]
            }
        }
    }
}
]