Mongodb - aggregation $push if conditional

24,177

Solution 1

This is my answer to the question after reading the post suggested by @Veeram

db.collection.aggregate([{
"$group":{
    "field": {
        "$push": {
            "$cond":[
                {"$gt":["$A", 0]},
                {"id": "$_id", "A":"$A"},
                null
            ]
        }
    },
    "secondField":{"$push":"$B"}
},
{
    "$project": {
        "A":{"$setDifference":["$A", [null]]},
        "B":"$B"
    }
}])

Solution 2

You can use "$$REMOVE":

  • This system variable was added in version 3.6 (mongodb docs)
db.collection.aggregate([{
   $group:{
       field: {
          $push: {
              $cond:[
                { $gt: ["$A", 0] },
                { id: "$_id", A:"$A" },
                "$$REMOVE"
            ]
          }
        },
        secondField:{ $push: "$B" }
    }
])

In this way you don't have to filter nulls.

Solution 3

One more option is to use $filter operator:

db.collection.aggregate([
{ 
    $group : {
        _id: null,
        field: { $push: { id: "$_id", A : "$A"}},
        secondField:{ $push: "$B" }
    }
},
{
    $project: {
        field: {
            $filter: {
                input: "$field",
                as: "item",
                cond: { $gt: [ "$$item.A", 0 ] }
            }
        },
        secondField: "$secondField"
    }       
}])

On first step you combine your array and filter them on second step

Share:
24,177
Artorias
Author by

Artorias

Updated on July 30, 2020

Comments

  • Artorias
    Artorias almost 4 years

    I am trying to aggregate a batch of documents. There are two fields in the documents I would like to $push. However, lets say they are "_id" and "A" fields, I only want $push "_id" and "A" if "A" is $gt 0.

    I tried two approaches.

    First one.

    db.collection.aggregate([{
    "$group":{
        "field": {
            "$push": {
                "$cond":[
                    {"$gt":["$A", 0]},
                    {"id": "$_id", "A":"$A"},
                    null
                ]
            }
        },
        "secondField":{"$push":"$B"}
    }])
    

    But this will push a null value to "field" and I don't want it.

    Second one.

    db.collection.aggregate([{
    "$group":
        "field": {
            "$cond":[
                {"$gt",["$A", 0]},
                {"$push": {"id":"$_id", "A":"$A"}},
                null
            ]
        },
        "secondField":{"$push":"$B"}
    }])
    

    The second one simply doesn't work...

    Is there a way to skip the $push in else case?

    ADDED:

    Expected documents:

    {
        "_id":objectid(1),
        "A":2,
        "B":"One"
    },
    {
        "_id":objectid(2),
        "A":3,
        "B":"Two"
    },
    {
        "_id":objectid(3),
        "B":"Three"
    }
    

    Expected Output:

    {
        "field":[
            {
                "A":"2",
                "_id":objectid(1)
            },
            {
                "A":"3",
                "_id":objectid(2)
            },
        ],
        "secondField":["One", "Two", "Three"]
    }