CRUD Operations - Reading and Querying Documents
Now that you've learned how to create documents in MongoDB, it's time to master the art of retrieving them. In this lesson, you'll learn how to read and query documents using MongoDB's powerful querying capabilities.
Learning Goals:
- Use
find()andfindOne()to retrieve documents - Apply query filters to search for specific data
- Understand projection to control returned fields
- Work with comparison and logical operators
- Sort and limit query results
The find() Method
The find() method is your primary tool for retrieving documents from a collection. It returns a cursor that you can iterate over to access matching documents.
// Connect to database and collection
const database = client.db("company");
const employees = database.collection("employees");
// Find all documents in the collection
const allEmployees = await employees.find({}).toArray();
console.log("All employees:", allEmployees);
// Find documents matching specific criteria
const itEmployees = await employees.find({ department: "IT" }).toArray();
console.log("IT employees:", itEmployees);
findOne() for Single Documents
When you only need one document, findOne() is more efficient as it returns the first matching document directly.
// Find a single employee by name
const employee = await employees.findOne({ name: "Alice Johnson" });
console.log("Found employee:", employee);
// Find first employee in IT department
const firstIT = await employees.findOne({ department: "IT" });
console.log("First IT employee:", firstIT);
Use findOne() when you expect exactly one result or only need the first match. Use find() when you need multiple documents or want to process results in batches.
Query Filters and Operators
MongoDB provides powerful operators to create complex queries. Let's explore the most commonly used ones.
Comparison Operators
// Find employees with salary greater than 50000
const highEarners = await employees.find({
salary: { $gt: 50000 }
}).toArray();
// Find employees with salary between 40000 and 60000
const midRange = await employees.find({
salary: { $gte: 40000, $lte: 60000 }
}).toArray();
// Find employees not in IT department
const nonIT = await employees.find({
department: { $ne: "IT" }
}).toArray();
Logical Operators
// Find employees in IT OR Engineering departments
const techEmployees = await employees.find({
$or: [
{ department: "IT" },
{ department: "Engineering" }
]
}).toArray();
// Find senior IT employees (IT department AND salary > 60000)
const seniorIT = await employees.find({
$and: [
{ department: "IT" },
{ salary: { $gt: 60000 } }
]
}).toArray();
Projection: Controlling Returned Fields
Projection allows you to specify which fields to include or exclude in the results, reducing network overhead and improving performance.
// Include only name and department fields
const namesAndDepts = await employees.find(
{ department: "IT" },
{ projection: { name: 1, department: 1 } }
).toArray();
// Exclude the _id field from results
const noIds = await employees.find(
{},
{ projection: { _id: 0, name: 1, department: 1 } }
).toArray();
// Exclude salary field (include all others)
const noSalaries = await employees.find(
{},
{ projection: { salary: 0 } }
).toArray();
You cannot mix inclusion and exclusion in the same projection (except for the _id field). Choose either to include specific fields or exclude specific fields.
Sorting and Limiting Results
Control the order and quantity of returned documents for better data presentation and performance.
// Get top 5 highest paid employees
const topEarners = await employees.find({})
.sort({ salary: -1 }) // -1 for descending, 1 for ascending
.limit(5)
.toArray();
// Get newest employees (assuming createdAt field)
const newest = await employees.find({})
.sort({ createdAt: -1 })
.limit(10)
.toArray();
// Pagination example: skip first 10, get next 10
const secondPage = await employees.find({})
.sort({ name: 1 })
.skip(10)
.limit(10)
.toArray();
Array Query Operations
Querying arrays requires special operators to match elements within array fields.
// Find employees with specific skill
const javascriptDevs = await employees.find({
skills: "JavaScript"
}).toArray();
// Find employees with ALL specified skills
const fullStack = await employees.find({
skills: { $all: ["JavaScript", "Node.js", "React"] }
}).toArray();
// Find employees with array size greater than 3
const skilledEmployees = await employees.find({
skills: { $size: { $gt: 3 } }
}).toArray();
Multi-language Examples
- JavaScript
- TypeScript
// Complete example using async/await
async function findSeniorDevelopers() {
const seniors = await employees.find({
$and: [
{ title: "Senior Developer" },
{ salary: { $gte: 80000 } },
{ yearsExperience: { $gte: 5 } }
]
})
.sort({ salary: -1 })
.limit(5)
.toArray();
return seniors;
}
interface Employee {
_id: ObjectId;
name: string;
department: string;
salary: number;
skills: string[];
}
async function findSeniorDevelopers(): Promise<Employee[]> {
const seniors = await employees.find<Employee>({
$and: [
{ title: "Senior Developer" },
{ salary: { $gte: 80000 } },
{ yearsExperience: { $gte: 5 } }
]
})
.sort({ salary: -1 })
.limit(5)
.toArray();
return seniors;
}
Common Pitfalls
- Missing
.toArray(): Forgetting to call.toArray()onfind()results leaves you with a cursor instead of actual documents - Mixed projection syntax: Trying to include some fields and exclude others in the same projection (except
_id) - Case sensitivity: String queries are case-sensitive; use regex or collation for case-insensitive searches
- ObjectId comparison: When querying by
_id, remember to useObjectIdtype, not plain strings - Performance with large datasets: Always use projection to limit returned fields and apply appropriate limits
Summary
In this lesson, you've learned how to effectively read and query documents in MongoDB:
- Use
find()for multiple documents andfindOne()for single documents - Apply query filters with comparison (
$gt,$lt, etc.) and logical operators ($and,$or) - Control returned fields with projection to improve performance
- Sort and limit results for better data presentation
- Query array fields using specialized array operators
These skills form the foundation of data retrieval in MongoDB and are essential for building efficient applications.
Quiz
Show quiz
-
What is the key difference between
find()andfindOne()? -
How would you find all documents where the "age" field is greater than 25?
-
What's wrong with this projection:
{ name: 1, age: 1, salary: 0 }? -
How do you sort results in descending order by a "createdAt" field?
-
Which operator would you use to find documents that have ALL specified values in an array field?
Answers:
find()returns a cursor for multiple documents, whilefindOne()returns a single document directlydb.collection.find({ age: { $gt: 25 } })- You cannot mix inclusion (name:1, age:1) and exclusion (salary:0) in the same projection
.sort({ createdAt: -1 })- The
$alloperator:{ field: { $all: ["value1", "value2"] } }