Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to get single result in aggregate?

Tags:

mongodb

Is it possible to get a single document on db.collection.aggregate like as in db.collection.findOne?

like image 612
Erik Avatar asked Oct 15 '14 05:10

Erik


People also ask

How do I find one record in MongoDB?

MongoDB – FindOne() Method. The findOne() method finds and returns one document that matches the given selection criteria. If multiple documents satisfy the given query expression, then this method will return the first document according to the natural order which reflects the order of documents on the disk.

Is aggregate faster than find?

Without seeing your data and your query it is difficult to answer why aggregate+sort is faster than find+sort. A well indexed(Indexing that suits your query) data will always yield faster results on your find query.

What is $$ root in MongoDB?

The $$ROOT variable contains the source documents for the group. If you'd like to just pass them through unmodified, you can do this by $pushing $$ROOT into the output from the group.

What is $project in MongoDB?

Definition. $project. Passes along the documents with the requested fields to the next stage in the pipeline. The specified fields can be existing fields from the input documents or newly computed fields.


2 Answers

Yes, it is possible. Just add a $group stage with _id equal to null. That will calculate accumulated values for all the input documents as a whole. E.g.

{ $group: { _id: null, total: { $sum: "$price" }}} 

Or if you want to get only one document from aggregated results, you can use $limit:

{ $limit: 1 } 

UPDATE: Both these solutions return cursor which would have single document. But don't think about findOne as something special. It also retrieves cursor and just gets first document (if any). Here is mongo shell implementation of findOne:

function ( query , fields, options ){     var cursor = this.find(query, fields, -1 /* limit */, 0 /* skip*/,         0 /* batchSize */, options);      if ( ! cursor.hasNext() )         return null;     var ret = cursor.next();     if ( cursor.hasNext() ) throw "findOne has more than 1 result!";     if ( ret.$err )         throw "error " + tojson( ret );     return ret; } 

As you can see, it internally uses find. So, if you want to get single document instead of cursor with single document, you can write your own function which does same with aggregate. E.g.

> DBCollection.prototype.aggregateOne = function(pipeline) {      var cur = this.aggregate(pipeline);      if (!cur.hasNext())          return null;       return cur.next();   } 

Usage:

> db.collection.aggregateOne(...) 
like image 56
Sergey Berezovskiy Avatar answered Sep 22 '22 19:09

Sergey Berezovskiy


It is possible to add $match stage to aggregation pipeline. But even if it will match only one single document, then result will still be a list (of length one in that case). So the answer is "NO, it is not possible".

like image 21
stalk Avatar answered Sep 21 '22 19:09

stalk