How to $push a field depending on a condition?

人盡茶涼 提交于 2019-12-12 19:23:27

问题


I'm trying to conditionally push a field into an array during the $group stage of the MongoDB aggregation pipeline.

Essentially I have documents with the name of the user, and an array of the actions they performed.

If I group the user actions like this:

{ $group: { _id: { "name": "$user.name" }, "actions": { $push: $action"} } }

I get the following:

[{
    "_id": {
        "name": "Bob"
    },
    "actions": ["add", "wait", "subtract"]
}, {
    "_id": {
        "name": "Susan"
    },
    "actions": ["add"]
}, {
    "_id": {
        "name": "Susan"
    },
    "actions": ["add, subtract"]
}]

So far so good. The idea would be to now group together the actions array to see which set of user actions are the most popular. The problem is that I need to remove the "wait" action before taking into account the group. Therefore the result should be something like this, taking into account that the "wait" element should not be considered in the grouping:

[{
    "_id": ["add"],
    "total": 1
}, {
    "_id": ["add", "subtract"],
    "total": 2
}]

Test #1

If I add this $group stage:

{ $group : { _id : "$actions", total: { $sum: 1} }}

I get the count that I want, but it takes into account the unwanted "wait" array element.

[{
    "_id": ["add"],
    "total": 1
}, {
    "_id": ["add", "subtract"],
    "total": 1
}, {
    "_id": ["add", "wait", "subtract"],
    "total": 1
}] 

Test #2

{ $group: { _id: { "name": "$user.name" }, "actions": { $push: { $cond: { if: 
{ $ne: [ "$action", 'wait']}, then: "$action", else: null } }}} }


{ $group : { _id : "$actions", total: { $sum: 1} }}

This is as close as I've gotten, but this pushes null values where the wait would be, and I can't figure out how to remove them.

[{
    "_id": ["add"],
    "total": 1
}, {
    "_id": ["add", "subtract"],
    "total": 1
}, {
    "_id": ["add", null, "subtract"],
    "total": 1
}]

UPDATE:

My simplified documents look like this:

{
    "_id": ObjectID("573e0c6155e2a8f9362fb8ff"),
    "user": {
        "name": "Bob",
    },
    "action": "add",
}

回答1:


You need a preliminary $match stage in your pipeline to select only those documents where "action" is not equals to "wait".

db.collection.aggregate([
    { "$match": { "action": { "$ne": "wait" } } },
    { "$group": { 
        "_id": "$user.name", 
       "actions": { "$push": "$action" }, 
       "total": { "$sum": 1 } 
    }}
])


来源:https://stackoverflow.com/questions/37376999/how-to-push-a-field-depending-on-a-condition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!