ObjectId & MongoDB Cursor
ObjectId is MongoDB's default _id type — a 12-byte value guaranteed unique across a sharded cluster. It embeds a 4-byte timestamp (creation time), 5-byte random value, and 3-byte counter.
ObjectId structure
ObjectId is MongoDB's default _id type — a 12-byte value guaranteed unique across a sharded cluster. It embeds a 4-byte timestamp (creation time), 5-byte random value, and 3-byte counter.
You can inspect ObjectId.getTimestamp() in mongosh to see when a document was created (approximate to insertion second).
Real-life example: ObjectId is a ticket number with hidden metadata — the counter clerk (MongoDB) knows when it was issued and guarantees no duplicate ticket in the venue.
- 12 bytes — compact compared to UUID strings in every index
- Timestamp component — rough creation time without a separate field
- Generated automatically if _id is omitted on insert
- Custom _id allowed — string, UUID, or compound key if you design for it
const doc = db.users.insertOne({ name: "Test User" })
const id = doc.insertedId
id // ObjectId('...')
id.getTimestamp() // ISODate — creation second
db.users.findOne({ _id: id })
// Create ObjectId from string (must be valid 24 hex chars)
ObjectId("665a1b2c3d4e5f6789012345")What is a cursor?
find() does not return all documents at once — it returns a cursor, a pointer that streams results from the server in batches. This keeps memory low on large collections.
Call toArray() to load everything into an array (fine for small sets). Use forEach or async iteration in drivers for large result sets.
Real-life example: A cursor is a Netflix playlist — titles load in chunks as you scroll, not the entire catalog downloaded before you press play.
const cursor = db.users.find({ active: true })
// Iterate with forEach
cursor.forEach(doc => print(doc.name))
// Load all into array (small results only)
const all = db.users.find().toArray()
// Manual next()
const c = db.users.find()
printjson(c.next())
printjson(c.hasNext())Cursor methods — limit, skip, sort, count
Chain limit(n) to cap results, skip(n) for pagination offsets, sort({ field: 1 }) for ascending order (-1 descending). countDocuments(filter) counts matches; deprecated cursor.count() is replaced by countDocuments in modern shell.
Sort + skip + limit order matters — sort first, then skip, then limit for stable pagination.
Real-life example: limit/skip/sort are search filters on a shopping site — sort by price, skip first 20 items (page 2), show 10 per page (limit).
- limit(n) — return at most n documents
- skip(n) — skip first n (pagination; use with indexes on sort field)
- sort({ field: 1 | -1 }) — 1 ascending, -1 descending
- countDocuments(filter) — accurate count; may scan if no index
// Newest 5 active users
db.users
.find({ active: true })
.sort({ createdAt: -1 })
.limit(5)
// Page 3 — 10 per page (skip 20)
db.users
.find()
.sort({ name: 1 })
.skip(20)
.limit(10)
// Count matching documents
db.users.countDocuments({ active: true })