Home > Mobile >  Aggregation: How would I count the number of keys for which the value is true?
Aggregation: How would I count the number of keys for which the value is true?

Time:05-24

I have a load of documents in mongodb which look something like this:

[
  {
    name: "steve",
    accountFeatures: {word: true, excel: false, powerpoint: true}
  },
  {
    name: "john",
    accountFeatures: {word: false, excel: true, powerpoint: true, notes: true}
  },
  {
    name: "rick",
    accountFeatures: {word: true, excel: false, powerpoint: true}
  }
]

I want to run an aggregation to find out how many of each of the keys in the objects are set to true (there are many more keys in the actual data), so the expected output for the sample data would be:

  {
    "res": {
      "excel": 1,
      "notes": 1,
      "powerpoint": 3,
      "word": 2
    }
  }

Is this possible? So far all I can think to do is this:

[
  {
    '$project': {
      '_id': 0, 
      'accountFeatures': 1
  }
]

CodePudding user response:

You can use $objectToArray and $unwind which will allow us $group by the keys:

db.collection.aggregate([
  {
    $set: {accountFeatures: {$objectToArray: "$accountFeatures"}}
  },
  {
    $project: {
      accountFeatures: {
        $filter: {
          input: "$accountFeatures",
          as: "item",
          cond: {$eq: ["$$item.v", true]}
        }
      }
    }
  },
  {
    $unwind: "$accountFeatures"
  },
  {
    $group: {_id: "$accountFeatures.k", v: {$sum: 1}}
  },
  {
    $group: {_id: 0, data: {$push: {k: "$_id", v: "$v"}}}
  },
  {
    $project: {res: {$arrayToObject: "$data"}, _id: 0}
  }
])
  1. $objectToArray to extract the keys
  2. $filter to keep only the true ones
  3. $unwind to separate the keys to different documents
  4. $group to count each key
  5. format the results Playground example
  • Related