Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js : How to return Object in Query Aggregation?

I need to calculate sum for specified field from my collection using group by

So that, I used aggregate function.

My wish is function should return Object only. When I use aggregate, it returns the Array of Objects.

But my query was returns Array of objects ([{..}, {..}, {..}]) not single object({..}) .

For example, So far I tried

Specified with Array [ ] structure

MyModel.aggregate(
  [
    {$match : ... },
    {$group : ... }
  ], function(err, result) {
      console.log(result);
}); 

Specified without Array [ ] structure

MyModel.aggregate(
    {$match : ... },
    {$group : ... }
  , function(err, result) {
      console.log(result);
});

The above both scenarios returns the same. like,

[
  {
    ...
    ...
  }
]

My expected result only an object

{
  ...
  ...
}
like image 246
Ranjith Avatar asked Aug 25 '14 09:08

Ranjith


1 Answers

Officially, the aggregate command takes a "list" of pipeline arguments as it's main input. This is why the "Array" syntax is preferred. Though it is not strictly implemented this way by the mongoose method you appear to be using, this is likely to change.

The "Official" arguments are

  1. An array representing the pipeline conditions

  2. An options document specifying various options to alter the behavior.

So the mongoose form here is just looking for which item in the "list" is a function() and considers everything beforehand to be pipeline. But this will have to change in the future. Your question though seems to be more about "expecting" the different form to produce either a "document" or an "array" in response. But this will not happen.

You don't really and there is a good reason why. The aggregation framework either performs manipulation on collection content just as with $project or otherwise "groups" information such as with $group.

The only ways in which you generally expect only "one" result to return is when you either specifically $match to obtain only one result or otherwise $limit the response to one or even if your $group is on a singular or null value.

It is generally expected to be a "collection" of results or here represented as an array. Modern MongoDB servers and driver implementations can in fact return a "cursor", so the results can be larger than the 16MB BSON limit with newer versions. But still basically a list.

So it's always an array at present with something like "mongoose", which it looks like you are using. Just return the "first element" when it is all you want. Possibly even limit to 1 as well:

MyModel.aggregate(
  [
    { "$match": ... },
    { "$group": ... },
    { "$limit": 1 }
  ], function(err, result) {
      console.log(result[0]);
});

Which is essentially all that methods like .findOne() are doing under the covers anyway.

like image 167
Neil Lunn Avatar answered Oct 20 '22 02:10

Neil Lunn