如何在mongo聚合中使用$ in或$ nin $ group $ cond [英] How to use $in or $nin in mongo aggregation $group $cond

查看:134
本文介绍了如何在mongo聚合中使用$ in或$ nin $ group $ cond的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过在属性上设置$ or来用$ 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
              ] 
           }
         }
    }  
 }
)

但是错误提示: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
              ] 
           }
         }
   }  
 }
)

解决方案

$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
                ]
            }
        }
    }}    
])
 

或者,如果愿意,可以使用 $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
                ]
            }
        }
    }}
])
 

$map只是遍历参数以匹配单数,而不是将单数强制为数组.

当然,由于这两种形式本质上都是为$cond提供true/false,因此您可以使用 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 ] } } }} ])

这实际上取决于您的外观,但是仅作为提供的参数,使用$or并不会真正获得超过原始形式的任何东西.看起来可能更简洁,更容易键入,但是通常我不会直接在聚合管道中键入"这种逻辑,而是首先基于简单列表生成结构的那部分:

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

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

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

     { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$or": orCondition },
                    1,
                    0
                ]
            }
        }
    }}
])
 

无论您以何种方式看待它,请记住,它们全都是数据结构,并且具有基本的操作过程.不仅在管道处理内部,而且在管道构建本身中.

I want to achieve $sum with $cond by having $or on property:

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
              ] 
           }
         }
    }  
 }
)

But error says: Invalid operator "$id"

What's wrong with syntax? Or I am writing query wrongly.

Currently I am achieving this by:

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
              ] 
           }
         }
   }  
 }
)

解决方案

The comparison on $setIsSubset is a shorter option than the $or condition you are using, though it's still basically valid to do what you are doing.

The only catch with $setIsSubset is that each argument is an array so you need to convert the single element as a single element array. This is easy enough using $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
                ]
            }
        }
    }}    
])

Or if you prefer, then match the array of arguments against the singular value instead, with $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
                ]
            }
        }
    }}
])

Where the $map is rather traversing the arguments to match to the singular rather than forcing the singular into an array.

And of course since either form is essentially supplying true/false to the $cond then you can just reverse the logic with $not where required:

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
                ]
            }
        }
    }}
])

It really depends on how you look at it, but simply as supplied arguments then you don't really gain anything over the original form with $or. It might look a little cleaner and "easier to type", but typically I would not be "typing" such logic into the aggregation pipeline directly, but rather generating that part of the structure based on a plain list in the first place:

i.e

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

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

And then just using the re-mapped array content in the pipeline definition:

    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$or": orCondition },
                    1,
                    0
                ]
            }
        }
    }}
])

Whatever way you look at it, remember it's all just data structures and you have basic processes for manipulating. Both inside the pipeline processing and also in the pipeline construction itself.

这篇关于如何在mongo聚合中使用$ in或$ nin $ group $ cond的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆