Query Documents with find()

Learn how to query documents with find() basics in MongoDB — covers the core concepts, hands-on exercises, troubleshooting, and next steps.

Focus: query documents with find() basics

Sponsored

You've successfully inserted documents into MongoDB, but now the real work begins: getting data back out. The find() method is your primary tool for querying documents in MongoDB, and it's deceptively simple. Yet, without a solid grasp of its basics, you'll quickly find yourself either returning entire collections or writing overly complex queries that miss the mark. In this lesson, you'll learn the fundamentals of find() — from selecting all documents to filtering with query predicates and projecting specific fields — so you can confidently retrieve exactly what you need, every time.

The problem this lesson solves

When you start working with MongoDB, you often know the collection you need, but not how to efficiently pull the right documents out of it. Running db.collection.find() with no arguments returns every document in a collection — which is fine for a tiny test database, but useless when your collection holds thousands or millions of records. This lesson solves the core problem of intentional querying: how to use find() to retrieve all documents, subset them by criteria, and shape the output to fit your application's needs. Without this skill, you'll waste bandwidth, slow down your app, and struggle to build meaningful features.

Core concept / mental model

Think of find() as a filter and a projector combined into one method. The first argument is the query predicate — the filter that says which documents to return. The second argument is the projection — the set of fields to include or exclude for each match. If you can visualize these two layers, you've already understood the essence of find().

In MongoDB, documents are stored as BSON (Binary JSON), and queries are written as JSON-like documents. Each key-value pair in the query document represents a condition that a matching document must satisfy. For example, {age: 25} matches documents where the age field equals exactly 25. This declarative style is intentional: you describe what you want, not how to get it.

Here's a simple diagram-in-words:

Collection: books
[
  {title: "Moby Dick", author: "Herman Melville", year: 1851, pages: 635},
  {title: "1984", author: "George Orwell", year: 1949, pages: 328},
  {title: "Brave New World", author: "Aldous Huxley", year: 1932, pages: 311}
]

Query: {year: 1949}
Result: [ {title: "1984", author: "George Orwell", year: 1949, pages: 328} ]

The filter sits on top of the collection and lets through only documents that satisfy all conditions. The projection then trims each passing document to the fields you actually need.

How it works step by step

To use find() effectively, follow this mental sequence:

  1. Connect to your databaseuse mydb in the mongosh shell.
  2. Identify the collection — for example, books.
  3. Decide on your filter — what must be true about a document to match? Start with simple equality, then expand to operators like $gt, $lt, $in, or $regex.
  4. Call find() with the predicatedb.books.find({year: 1949}).
  5. Optionally, add a projection — the second argument to limit fields returned, e.g., {title: 1, _id: 0}.
  6. Iterate the cursor — in the shell, the cursor prints the documents; in code, you loop over the cursor to process results.

Cause and effect: a missing filter causes all documents to match — that's the default behavior. Adding a predicate narrows the result set. Adding a projection shapes each output document, which can reduce network payload and improve performance.

The projection syntax is worth memorizing: - 1 includes a field (like {title: 1}). - 0 excludes a field (like {author: 0}). - You cannot mix include and exclude except for the _id field.

Hands-on walkthrough

Let's make this concrete. Start your mongosh shell and set up a sample collection. Run the following to insert some books:

// Switch to (or create) the library database
use library

// Insert sample books
const books = [
  { title: "Moby Dick", author: "Herman Melville", year: 1851, pages: 635, genre: "Novel" },
  { title: "1984", author: "George Orwell", year: 1949, pages: 328, genre: "Dystopian" },
  { title: "Brave New World", author: "Aldous Huxley", year: 1932, pages: 311, genre: "Dystopian" },
  { title: "The Great Gatsby", author: "F. Scott Fitzgerald", year: 1925, pages: 180, genre: "Novel" }
]

db.books.insertMany(books)

Now, let's practice the basics:

1. Find all documents

db.books.find()

Expected output: all four documents, printed in the shell.

2. Filter by equality

db.books.find({genre: "Dystopian"})

Expected output: the two Dystopian books (1984 and Brave New World).

3. Use multiple conditions (AND)

db.books.find({ author: "George Orwell", year: 1949 })

Expected output: only the 1984 document.

4. Projection — return only title and pages, exclude _id

db.books.find({ genre: "Novel" }, { title: 1, pages: 1, _id: 0 })

Expected output: documents containing only title and pages for the two Novels.

5. Use comparison operators

db.books.find({ pages: { $gt: 200 } })

Expected output: all books except the Great Gatsby (180 pages).

Pro tip: Always pass projection when you only need a handful of fields. This reduces the amount of data transferred and speeds up your application.

Compare options / when to choose what

The find() method has several variations and companion methods. Here's a quick comparison:

Method/stage Purpose When to use
find({ filter }) Return multiple documents Standard querying — always your first choice
findOne({ filter }) Return first matching document When you expect only one result, e.g., fetching a user by ID
countDocuments({ filter }) Count matches without returning docs When you only need a number, e.g., pagination totals
find({}).sort() Sort results When order matters (combine with limit())
find({}).limit(n) Limit result set When you need a specific number of docs, e.g., top-10
find().skip(n) Skip documents For pagination (often with sort)

In practice, you'll combine find() with sort(), limit(), and skip(). For example, to get the oldest book, you might do:

db.books.find().sort({ year: 1 }).limit(1)

Expected output: The Great Gatsby (1925).

Troubleshooting & edge cases

Even a simple find() can trip you up. Here are common pitfalls and fixes:

  • You get no results but expect some. Check the exact field name and value. String case matters: {author: "george orwell"} won't match "George Orwell". Also, ensure the collection name is correct — books vs book is an easy typo.
  • Projection mixing error. If you combine include and exclude fields (e.g., {title: 1, author: 0}), MongoDB throws an error: Cannot do exclusion on field author in inclusion projection. Remember the rule: only mix with _id.
  • Document fields stored as numbers vs strings. If year is stored as a string "1949", then {year: 1949} (number) won't match. Use {year: "1949"} or store consistent types.
  • Equality on arrays. If a field is an array, {tags: "mongodb"} matches documents where the array contains that element. If you need exact array equality, use {tags: ["mongodb", "database"]} — this matches only if the array matches exactly (order included).
  • Missing field behavior. Documents missing the queried field won't match an equality filter. If you need to include them, use $exists.

What you learned & what's next

You now understand the core mechanics of find(): filtering with query predicates, projecting fields, and combining with sort and limit. You can retrieve all documents, apply equality and comparison filters, and control the output shape. This is the foundation for all MongoDB querying — from simple lookups to complex aggregations.

Next, you'll deepen your query vocabulary by exploring advanced query operators like $in, $or, and $regex, and then dive into updating documents with updateOne() and updateMany(). These skills build directly on what you've learned here, so you're ready to move forward with confidence.

Practice recap

Now it's your turn: insert a collection of your own (e.g., movies with title, year, rating) and practice using find() to filter by a field, project only essential fields, sort by year, and limit to the top 3. Try adding a countDocuments() query to check your assumptions. This hands-on repetition will cement your understanding before moving to advanced query operators.

Common mistakes

  • Forgetting to pass a filter when you only need a subset — find() with no args returns the entire collection, which can be slow and wasteful.
  • Mixing inclusion and exclusion projections (e.g., {title: 1, author: 0}) — MongoDB throws an error. Remember: only _id can be mixed.
  • Mismatched data types — querying {year: 1949} when the stored value is a string "1949" yields no results for equality.
  • Expecting find() with an array field to match exactly — {tags: "mongodb"} matches arrays containing that element, not arrays exactly equal.
  • Using findOne() when multiple results are possible — if you need all matches, use find(), not findOne(), which returns only the first.

Variations

  1. Use findOne() for single-document retrieval, especially for lookups by unique fields like _id.
  2. Combine find() with sort(), skip(), and limit() for pagination and ordered results.
  3. For counting matches without fetching documents, use countDocuments() instead of find().count().

Real-world use cases

  • Search a product catalog by category and price range using find({ category: "electronics", price: { $gte: 100, $lte: 500 } }).
  • Fetch a user profile by their email address with findOne({ email: "user@example.com" }) for login or account display.
  • Read recent blog posts by filtering on published: true and sorting by date descending, then limiting to 10 results.

Key takeaways

  • The find() method takes an optional query predicate and optional projection to filter and shape results.
  • Using no predicate returns all documents; adding {} as the first argument has the same effect.
  • Projection allows including or excluding fields, but mixing inclusion and exclusion (except _id) causes an error.
  • Comparison and logical operators like $gt, $lt, $in, and $or are essential for building robust queries.
  • Combine find() with sort(), limit(), and skip() for practical use cases like pagination and top-N lists.
  • Always verify field names and data types to avoid empty result sets from mismatched conditions.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.