2

I am fairly new to working with MongoDB.

I need to retrieve the previous record of a given record in a MongoDB collection.

  1. Is it possible to do this with "_id = ObjectId(...)" field?
  2. If not, will we have to explicitly insert a key with a sequential value to identify the previous record to the given one? (Assume that there's no sequential key/value pair in the current collection)

Would greatly appreciate any help. Thank you.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
hel
  • 453
  • 4
  • 12

2 Answers2

4

All things being equal, the default value of the _id field is a ObjectId and is monotonic, or ever increasing.

This means that given a known ObjectId value then the following is true to retrieve the document that was inserted immediately before it:

db.collection.find(
    { "_id": { "$lt": ObjectId("538c271a19b3a188ca6135eb") }}
).sort({ "_id": -1 }).limit(1)

That is the general case. The only possible variance is that various sources are producing the ObjectId values and their clocks are set to different times (as in completely different UTC times).

So that coupled with the rate of insertion allows you to consider if this is good enough for you, and with the exception of rare and poorly managed conditions it should never be the case that the order is not always maintained.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
2

May i suggest use indexes for best performance.

As an example: Create Indexes:

db.books.ensureIndex({book: 1}) // for next records in collection
db.books.ensureIndex({book: -1}) // for previous records in collection

Next query looks like:

db.books.find({book: {$gt:"a"}}).sort({book: 1}).hint({book: 1}).limit(1)

Previous query looks like:

db.books.find({book: {$lt:"b"}}).sort({book: -1}).hint({book: -1}).limit(1)
Abs
  • 3,902
  • 1
  • 31
  • 30
  • 1
    Perhaps I should point out that the `_id` field is always indexed and also the fastest point for the optimizer to access since it is the primary index that is always expected to be there. – Neil Lunn Jun 02 '14 at 09:29
  • Thank you all for the valuable feedback. I have done the below code using casbah in scala, for specifying indexes. Could you please tell me whether I'm on the right track. `val collection = MongoConnection()()() collection.ensureIndex(DBObject("days"-> 1)) val record = (collection.find("days" $lt begin)).sort(MongoDBObject("days" -> -1)).limit(1)` – hel Jun 02 '14 at 11:39
  • @hel Not sure why you accepted the answer that is the opposite to the question you actually asked. I only piped in late as this answer was given after the the one I already provided. If you want insertion order then use the `_id` field as has been explained. – Neil Lunn Jun 02 '14 at 12:37
  • Apologies for any wrong marking. Actually, there were two collections, one which we had to concern about the insertion order via "_id" field and, another collection which we had to concern the descending order of a "custom field" regardless of insertion order. Therefore, both the answers were of great help for us. Thanks again for sharing the valuable techniques. – hel Jun 02 '14 at 15:09
  • Note: for the simple index case (or where you are sorting by the last field in a compound index) you do not need to create both forward and reverse indexes. The same index can be used to sort in either direction. Additionally, aside from rare cases you almost never want to `hint()` index usage. Hinting forces the query optimizer to use a specific index and should be used sparingly unless you are certain the query optimizer is not doing the right thing. You can look at the query plan details via [`explain(true)`](http://docs.mongodb.org/manual/reference/method/cursor.explain/). – Stennie Jun 10 '14 at 07:38