Diolor
Diolor

Reputation: 13450

Aggregation $group return fields as string and not as array

I'm doing the following aggregation:

db.col.aggregate([
        {'$unwind': "$students"},
        {'$group':
            {
                "_id" : "$_id",
                'students' :
                    { '$push' :
                       {
                        'name' : '$students.name',
                        'school' : '$students.school',
                        'age' : '$students.age',
                       }
                    },
                'zipcode' :
                    {'$addToSet':
                        '$zipcode'
                    }
            }
        },
        {'$project':
            {
                '_id' : 0 ,
                'students' : 1,
                'zipcode': 1
            }
        }
])

Which gives:

{
   "result" : [
      {
        "students" : [{
                         "name" : "john",
                         "school" : 102,
                         "age" : 10
                      },
                      {
                         "name" : "jess",
                         "school" : 102,
                         "age" : 11
                      },
                      {
                         "name" : "barney",
                         "school" : 102,
                         "age" : 7
                      }
                    ],
        "zipcode" : [63109]
      }
   ],
   "ok" : 1
}

Is it possible to have make it return "zipcode" : 63109?

In practice this is what I want to have a returning result of the aggregation:

{
   "result" : [
      {
        "students" : [{
                         "name" : "john",
                         "school" : 102,
                         "age" : 10
                      },
                      {
                         "name" : "jess",
                         "school" : 102,
                         "age" : 11
                      },
                      {
                         "name" : "barney",
                         "school" : 102,
                         "age" : 7
                      }
                    ],
        "zipcode" : 63109
      }
   ],
   "ok" : 1
}

I tried in the $group to have "zipcode" : "$zipcode" but as the documentation says:

Every $group expression must specify an _id field. 
In addition to the _id field, $group expression can include 
computed fields. These other fields must use one of the following accumulators:

$addToSet
$first
$last
$max
$min
$avg
$push
$sum

Is there any workaround?

Upvotes: 1

Views: 1045

Answers (1)

Stennie
Stennie

Reputation: 65323

The zipcode value is returned as an array because you are using the $addToSet operator, which explicitly returns an array:

Returns an array of all the values found in the selected field among the documents in that group.

If your intention is actually to group by zipcode, you can instead use this as the grouping _id, eg:

db.col.aggregate([

        // Create a stream of documents from the students array
        {'$unwind': "$students"},

        // Group by zipcode
        {'$group':
            {
                "_id" : "$zipcode",
                'students' :
                    { '$push' :
                       {
                        'name' : '$students.name',
                        'school' : '$students.school',
                        'age' : '$students.age',
                       }
                    },
            }
        },

        // rename _id to zipcode
        {'$project':
            {
                '_id' : 0,
                'zipcode' : '$_id',
                'students' : 1,
            }
        }
])

Alternatively, you could use a group operator such as $first or $last to return a single zipcode value, but this probably isn't what you're after.

Upvotes: 1

Related Questions