Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get lastest N records of each group in mongodb?

I have a couple of entries for each cities. How to get lastest 3 entries of each city? Like:

City1
record 1
record 2
record 3

City2
record 1
record 2
record 3

City3
record 1
record 2
record 3

The schema:

var schema = mongoose.Schema({
  city: {type: String},
  title: {type: String},
  created: {type: Number, default: Math.floor(new Date() / 1000)}
})

The code I've tried:

Collection
.find('location $in ' + cities)
.aggregate({$group: {location: "$location"}})
.sort('created: 1')
.limit(3).exec(function(err, docs) { res.render('index', { hash: docs }); });

So, how to perform a query where I should have as result: 3 most recent titles of each city

like image 949
Fernanda Fentili Avatar asked Dec 17 '15 02:12

Fernanda Fentili


People also ask

Where is last item in MongoDB?

To find last object in collection, at first sort() to sort the values. Use limit() to get number of values i.e. if you want only the last object, then use limit(1).

What does $LAST do MongoDB?

Returns the value that results from applying an expression to the last document in a group of documents.

What is $first in MongoDB?

This means $first returns the first order type for the documents between the beginning of the partition and the current document.


1 Answers

In mongoDB 3.2 you can perform this by using the aggregate query of following form:

db.collection.aggregate(
  {$sort: {created: -1}},
  {$group: {_id:'$city', title:{$push: '$title'}},
  {$project: {_id:0, city: '$_id', mostRecentTitle: {$slice: ['$title', 0, 2]}}}
)

Its very difficult to achieve the same using mongoDB 3.0. A very dirty trick is there to achieve this in 3.0. It involves a couple of steps and other collection.

First do an aggregate and output the result to a temporary collection called 'aggr_out'

Query:

db.collection.aggregate([
  {$sort: {created: -1}},
  {$group: {_id:'$city', title:{$push: '$title'}},
  {$project: {city: '$_id', mostRecentTitle: '$title'}},
  {$out: 'aggr_out'}]
)

Using above query, mostRecentTitle will have all the recent titles ordered from index 0, 1, 2, ... If you are happy with this result using this as you already have the result in indexes 0,1 and 2 of mostRecentTitle. Other titles can be simple ignored in application side.

Still if you are not happy, do an update on the output collection 'aggr_out', and read data from this collection. The query is,

db.aggr_out.update(
  {},
  {$push: {
    mostRecentTitle: {$each:[], $slice:3}
    }
  }
)

The above operation will slice the mostRecentTitle array so that it has most recent three titles. Do a read on this collection to get your desired result.

like image 118
Sarath Nair Avatar answered Nov 15 '22 22:11

Sarath Nair