Retrieving Documents with find()
db.collection.find(filter, projection) is the core read operation in MongoDB. Called with no arguments, find() returns every document in the collection as a cursor; passing a filter object narrows results to documents matching those field-value pairs, and the query engine can use indexes to satisfy the filter without scanning the whole collection.
Cricket analogy: It is like asking a scorer for every ball bowled in a match versus asking only for deliveries bowled by Jasprit Bumrah — the narrower filter returns a focused subset instead of the full innings log.
findOne() and Cursor Methods
findOne(filter) returns the first matching document directly, not a cursor, which is convenient when you expect at most one result, such as a lookup by a unique field. find() itself returns a cursor that is lazily evaluated; chaining .sort(), .limit(), and .skip() lets you control ordering and pagination before the cursor is actually iterated with .toArray(), forEach(), or a for-await loop.
Cricket analogy: It is like asking the scorer for just the current striker's stats rather than the whole team sheet — findOne() hands you a single record directly instead of a list you'd have to page through.
Projections: Shaping the Returned Fields
The second argument to find() and findOne() is a projection that controls which fields are returned. Passing { name: 1, price: 1 } includes only those fields (plus _id unless explicitly excluded with _id: 0), while passing { description: 0 } excludes just that field and returns everything else. You cannot mix inclusion and exclusion in the same projection except for _id.
Cricket analogy: It is like requesting only a player's runs and strike rate from the full scorecard rather than every statistic recorded — a projection trims the response to just what you need.
// Find in-stock products under $50, sorted by price, projecting only name and price
db.products.find(
{ inStock: true, price: { $lt: 50 } },
{ name: 1, price: 1, _id: 0 }
)
.sort({ price: 1 })
.limit(10);
// Find a single product by its unique SKU
db.products.findOne({ sku: "MOU-2024-BLK" });A cursor returned by find() is lazy: MongoDB does not fetch all matching documents at once. It batches results from the server as you iterate, which is why chaining .sort(), .skip(), and .limit() before iteration is efficient — the server can apply them before sending data over the wire.
Query Performance and Explain Plans
Running .explain('executionStats') on a query reveals whether MongoDB used an index (IXSCAN) or scanned every document (COLLSCAN), along with the number of documents examined versus returned. A query that examines far more documents than it returns is a strong signal that a supporting index is missing, which becomes critical as collections grow past a few thousand documents.
Cricket analogy: It is like checking whether the analyst pulled Virat Kohli's batting stats from an indexed player database or manually scanned every ball of every match ever played — the indexed lookup is dramatically faster.
Calling .sort() on a field without a supporting index forces MongoDB to load all matching documents into memory to sort them, which can hit the 100MB memory limit for sort operations and throw an error unless allowDiskUse is enabled or an index backs the sort field.
- find(filter, projection) returns a cursor over matching documents; findOne() returns a single document directly.
- An empty filter {} matches every document in the collection.
- Projections control which fields are returned; you can't mix inclusion and exclusion except for _id.
- Cursors are lazy and support chaining .sort(), .skip(), and .limit() before iteration.
- .explain('executionStats') reveals whether a query used an index (IXSCAN) or a full scan (COLLSCAN).
- Sorting on an unindexed field can hit MongoDB's in-memory sort limit on large result sets.
- Queries that examine far more documents than they return usually need a supporting index.
Practice what you learned
1. What does db.collection.find({}) return?
2. What is the key difference between find() and findOne()?
3. In a projection, which of these is valid?
4. What does COLLSCAN in an explain('executionStats') output typically indicate?
5. Why is chaining .sort().limit() on a cursor generally efficient?
Was this page helpful?
You May Also Like
Query Operators
Master MongoDB's comparison, logical, element, and array query operators like $gt, $in, $and, $exists, and $elemMatch for precise filtering.
Inserting Documents
Learn how to add data to MongoDB collections with insertOne and insertMany, how _id is generated, and how schema flexibility affects inserts.
Updating Documents
Learn how to modify existing documents using updateOne, updateMany, replaceOne, update operators like $set and $inc, and upserts.