如何在mongo聚合$ group $ cond中使用$ in或$ nin

Som*_*luk 9 mongodb mongodb-query aggregation-framework

我希望通过拥有$或者财产来获得$ cond的$ sum:

db.collectionName.aggregate(
{
   "$group": {
     "_id":'$created_at',
     "count": {"$sum": 1},
     "count_failure": {
         "$sum": {
           "$cond": [
               {
                 "$id":
                  { "$in": [ 0,100,101,102,103,104,105 ] }
               }, 
               1,
               0
              ] 
           }
         }
    }  
 }
)
Run Code Online (Sandbox Code Playgroud)

但错误说: Invalid operator "$id"

语法有什么问题?或者我错误地写了查询.

目前我通过以下方式实现此目标

db.collectionName.aggregate(
{
   "$group": {
     "_id":'$created_at',
     "count": {"$sum": 1},
     "count_failure": {
         "$sum": {
           "$cond": [
               {
                 "$or":[
                  { "$eq": [ "$id", 0 ] },
                  { "$eq": [ "$id", 100 ]},
                  { "$eq": [ "$id", 101 ]},
                  { "$eq": [ "$id", 102 ]},
                  { "$eq": [ "$id", 103 ]},
                  { "$eq": [ "$id", 104 ]},
                  { "$eq": [ "$id", 105 ]}
                 ]
               }, 
               1,
               0
              ] 
           }
         }
   }  
 }
)
Run Code Online (Sandbox Code Playgroud)

Bla*_*ven 11

比较$setIsSubset是比$or你正在使用的条件更短的选项,尽管它仍然基本上有效地做你正在做的事情.

唯一的问题$setIsSubset是每个参数都是一个数组,因此您需要将单个元素转换为单个元素数组.这很容易使用$map:

db.collectionName.aggregate([
    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$setIsSubset": [
                        { "$map": {
                            "input": ["A"],
                            "as": "el",
                            "in": "$id"
                        }},
                        [ 0,100,101,102,103,104,105 ],
                    ]},
                    1,
                    0
                ]
            }
        }
    }}    
])
Run Code Online (Sandbox Code Playgroud)

或者如果您愿意,则将参数数组与奇异值相匹配,使用$anyElementTrue:

db.collectionName.aggregate([
    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$anyElementTrue": { "$map": {
                        "input": [ 0,100,101,102,103,104,105 ],
                        "as": "el",
                        "in": { "$eq": [ "$$el", "$id" ] }
                    }}},
                    1,
                    0
                ]
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

$map是相当遍历参数匹配奇异而不是强迫奇异到一个数组.

当然,由于这两种形式基本上提供true/false$cond,那么你可以只用反向逻辑$not在需要:

db.collectionName.aggregate([
    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$not": [{ "$anyElementTrue": { "$map": {
                        "input": [ 0,100,101,102,103,104,105 ],
                        "as": "el",
                        "in": { "$eq": [ "$$el", "$id" ] }
                    }}}]},
                    1,
                    0
                ]
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

这实际上取决于你如何看待它,但仅仅作为提供的参数,那么你并没有真正获得原始形式的任何东西$or.它可能看起来更清晰,"更容易键入",但通常我不会直接在聚合管道中"键入"这样的逻辑,而是首先基于普通列表生成结构的那部分:

var failList = [ 0,100,101,102,103,104,105 ];

var orCondition = failList.map(function(el) { 
    return { "$eq": [ "$id", el ] }
})
Run Code Online (Sandbox Code Playgroud)

然后只需在管道定义中使用重新映射的数组内容:

    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$or": orCondition },
                    1,
                    0
                ]
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

无论你怎样看待它,记住它只是数据结构,你有基本的操作过程.既在管道内部处理,也在管道建设本身.