I have been unable to find any documentation or examples on how to do this, but surely it's possible. Basically, I want to keep 20 of the most recent records. I want to order by a date (descending), skip 20, then remove the leftovers.
3 Answers
You can do it in two steps -- 1, store the 20 most recent _id
s and then 2, perform remove
with $nin
. Example code is below, which you can play with on my Saturn Fiddle. I use number
, but you can obviously use some UNIX time stamp for your purpose.
// Welcome to SaturnAPI!
// Start collaborating with MongoDB fiddles and accomplish more.
// Start your code below these comments.
// Create a new collection
var Posts = new Mongo.Collection(null);
//Insert some data
Posts.insert({
number: 1,
author: "Saturn Sam",
message: "Hello!"
});
Posts.insert({
number: 2,
author: "Saturn Sam2",
message: "Hello!"
});
Posts.insert({
number: 3,
author: "Saturn Sam3",
message: "Hello!"
});
var recent = Posts.find({number: {$gte: 2}}).fetch().map(function (thisPost) {
return thisPost._id;
});
// Remove all but recent
Posts.remove({_id: {$nin: recent}});
// Returns all remaining records
Posts.find({}).fetch()

- 5,902
- 4
- 43
- 77
-
Thanks for the reply! I'm hoping for a more atomic approach. To go non-atomically, I would think that it would be more efficient to do a sorted find with a skip to get the date of the 20th document, then remove everything older than that. I suppose there isn't a single command to do this? – Alex311 Sep 15 '15 at 20:13
-
For atomicity, the closest solution I can recommend is altering your remove query to use `$gt` or `$lt` instead of `sort` and `skip`. This could work if you are sorting by timestamps, etc. – FullStack Sep 16 '15 at 03:49
I will suggest to go for capped collection with limit of 20 documents. It will delete last on insertion of new one. Hope it will help

- 52
- 6
-
1This would work great, however, I made my question simple and left out the fact that that documents in this collection is grouped. That is, I want to maintain a max size of 20 documents for each subID, which capped collections cannot do. – Alex311 Sep 15 '15 at 22:09
As I mentioned in my comment to the capped collection answer, I have documents in my collection that I want grouped by a certain ID, then limited to the 20 most recent. This isn't the perfect answer since it doesn't atomically remove documents, but it seems to be the best option I have.
I find the 21st document in the sorted results. If a 21st document exists (because I could have only 20 or less), then I remove it and everything older than it for my category and subcategory.
_id
is an ObjectId
.
db.logs.find({'catID': catID, 'subID': subID}, {_id: 1}).sort({'_id': -1}).skip(20).limit(1, function (err, docs) {
if(!err && docs.length) {
// If there was a 21st _id, remove it and all logs older than it for that category and subcategory
db.logs.remove({'catID': catID, 'subID': subID, '_id': {$lte: mongojs.ObjectId(docs[0]._id)}}, callback);
return;
}
callback(err, docs);
});

- 378
- 3
- 12