1

I have next simplified collection

[
  {
    "key": 1,
    "array": [
      {        "check": true      },
      {        "check": false      },
      {        "check": true      }
    ]
  },
  {
    "key": 2
  }
]

I want to add field "count" with number of elements of array with "check"=true, so I expect next result

  {
    "key": 1,
    "array": [
      {        "check": true      },
      {        "check": false      },
      {        "check": true      }
    ],
    "count":2,
  },
  {
    "key": 2,
    "count": 0
  }
]

I have next query ( it is aggregation, because actually it one of stages of pipeline)

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$sum": {
          "$cond": {
            "if": {
              "$eq": ["$array.check",true],              
            },
            "then": 1,
            "else": 0,            
          }
        }
      },      
    }
  }
])

But I always get count=0.

Can you help me to find error in my query?

Here mongo playground

2
  • 1
    You can use the $reduce aggregation array operator to calculate the conditional count. Commented Jul 13, 2020 at 13:41
  • Thanks for your answers. Possibly $reduce is the best solution. I also try to understand, why my query is not working. Commented Jul 13, 2020 at 13:59

3 Answers 3

2

Instead of using $sum, you can use $filter to filter only the array with "check"=true, then check the size of the resulting array using $size.

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$size": {
          "$filter": {
            "input": { "$ifNull": ["$array", []] }, // default empty array if array is does not exist
            "cond": "$$this.check" // only keep the truthy check value
          }
        }
      }
    }
  }
])

Mongo Playground

Alternatively, if you want to use $sum, you could also map the array to an array of 0 and 1 according to the check value, using $map

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$sum": {
          "$map": {
            "input": { "$ifNull": ["$array", []] },
            "in": {
              "$cond": ["$$this.check", 1, 0]
            }
          }
        }
      }
    }
  }
])

Mongo Playground

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, it is possible solution, thanks. But I also try to understand, why sum with cond is not working.
Because you are using not using $sum in the $group stage. Your use of $sum accept and array expression and calculate the sum of the values in the array. You can not put conditional logic there.
You can do the aggregation with $unwind and then group with sum conditionally.
@Ragnar I have added an alternative using $sum with $map
1

Here is how to achieve this using $reduce

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$sum": {
          $reduce: {
            input: "$array",
            initialValue: 0,
            in: {
              $sum: [
                "$$value",
                {
                  $cond: [
                    "$$this.check",
                    1,
                    0
                  ]
                }
              ]
            }
          }
        }
      }
    }
  }
])

Mongo Playground

Comments

0

Using $reduce aggregation array expression operator,

db.test.aggregate( [
  { 
      $addFields: { 
          count: { 
              $reduce: { 
                  input: { $ifNull: [ "$array", [] ] }, 
                  initialValue: 0, 
                  in: { 
                      $cond: [ { $eq: [ "$$this.check", true ] }, 
                               { $add: [ "$$value", 1 ] }, 
                               "$$value" 
                      ] 
                  }
              }
          }
      }
  }
] )

gets a result as follows:

{
        "_id" : ObjectId("5f0c7b691c7c98bb49fd2b50"),
        "key" : 1,
        "array" : [
                {
                        "check" : true
                },
                {
                        "check" : false
                },
                {
                        "check" : true
                }
        ],
        "count" : 2
}
{ "_id" : ObjectId("5f0c7b691c7c98bb49fd2b51"), "key" : 2, "count" : 0 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.