Home > database >  Reduce mongo object array to total size within a map
Reduce mongo object array to total size within a map

Time:10-13

I have a mongo document like this where usage is a map, so field names are not constant, it contains an array of unique seats that I want to count for each object:

{
    "usage" : {
        "maxNumberOfAddresses" : {
            "seats" : [
                "193.34.136.242",
                "138.61.33.44",
                "96.160.197.255",
                "151.34.143.231",
                "255.90.212.146",
                "182.57.86.6",
                "102.171.187.32",
                "150.157.38.224",
                "207.156.239.153",
                "59.194.105.191"
            ]
        },
        "totalUsers" : {
            "seats" : [
                "123",
                "456",
                "789",
            ]
        }
    }
},

I want to construct an aggregation that would return an object with sizes for each seats array in a map:

{
    "usage" : {
        "maxNumberOfAddresses" : {
            "total" : 10
        },
        "totalUsers" : {
            "total" : 3
        }
    }
},

I've tried a query like this, but it seems the wildcard doesn't work inside usage

db.seats.projection({
       "usage.*.seats": {
          $cond: {
            if: { $isArray: 'usage.*.seats' },
            then: { total: 'usage.*.seats' },
            else: 'NA',
          },
        },
   })

Any idea how to properly construct a query like this?

CodePudding user response:

One option is using $objectToArray and $arrayToObject:

db.collection.aggregate([
  {$project: {usage: {$objectToArray: "$usage"}}},
  {$project: {usage: {
        $map: {
          input: "$usage",
          in: {k: "$$this.k",  v: {total: {$size: "$$this.v.seats"}}}}
      }
    }
  },
  {$project: {usage: {$arrayToObject: "$usage"}}}
])

See how it works on the playground example

  • Related