Tired of just watching tutorials and never really feeling sure you can handle MongoDB on your own? You’re not alone—and that frustrating feeling ends right here. This post gives you 100 MongoDB practice problems with clear, complete solutions that actually make sense.
You’ll start with everyday essentials like inserting, finding, and updating documents, then work up to truly exciting challenges: aggregation pipelines, indexing, data modeling, and performance tricks. Every problem is written in plain, simple language so you can try it yourself first, then check the solution and truly understand it—no more hunting through confusing docs.
Whether you’re just beginning to fall in love with NoSQL or you’re preparing for a dream job interview, these exercises will make learning fun, practical, and deeply rewarding. Pick a problem now and start feeling genuinely confident with MongoDB. You’ve got this!
Here are 100 MongoDB practice problems with solutions, using MongoDB shell syntax. They cover CRUD, querying, updates, indexing, aggregation, and more.
Try it: 100 Node.js practice problems with solutions
1. Switch to a Database
Switch to the database named practiceDB.
js
use practiceDB
2. Create a Collection Explicitly
Create a collection named products.
js
db.createCollection("products")
3. Insert a Single Document
Insert one product document into products with fields: name, price, category.
js
db.products.insertOne({ name: "Laptop", price: 1200, category: "Electronics" })
4. Insert Many Documents
Insert multiple employees into an employees collection.
js
db.employees.insertMany([
{ name: "Alice", department: "HR", salary: 60000 },
{ name: "Bob", department: "Engineering", salary: 80000 },
{ name: "Charlie", department: "Engineering", salary: 75000 }
])
5. Find All Documents
Retrieve all documents from the employees collection.
js
db.employees.find()
6. Pretty Print Results
Display all employees in a readable format.
js
db.employees.find().pretty()
7. Find One Document
Find the first document where name is “Alice”.
js
db.employees.findOne({ name: "Alice" })
8. Projection: Select Specific Fields
Retrieve only name and salary from all employees, without _id.
js
db.employees.find({}, { name: 1, salary: 1, _id: 0 })
9. Equality Filter
Find employees in the “Engineering” department.
js
db.employees.find({ department: "Engineering" })
10. Comparison Operators: Greater Than
Find employees with salary greater than 70000.
js
db.employees.find({ salary: { $gt: 70000 } })
11. Greater Than or Equal
Employees with salary >= 75000.
js
db.employees.find({ salary: { $gte: 75000 } })
12. Less Than
Employees with salary < 80000.
js
db.employees.find({ salary: { $lt: 80000 } })
13. Not Equal
Find employees whose department is not “HR”.
js
db.employees.find({ department: { $ne: "HR" } })
14. Multiple Conditions (AND)
Find Engineering employees with salary > 70000.
js
db.employees.find({ department: "Engineering", salary: { $gt: 70000 } })
15. OR Operator
Find employees in either “HR” or “Finance”.
js
db.employees.find({ $or: [ { department: "HR" }, { department: "Finance" } ] })
16. AND with OR
Employees in “Engineering” with salary > 70000 OR in “HR” with any salary.
js
db.employees.find({
$or: [
{ department: "Engineering", salary: { $gt: 70000 } },
{ department: "HR" }
]
})
17. IN Operator
Find employees whose department is one of [“Engineering”, “IT”].
js
db.employees.find({ department: { $in: ["Engineering", "IT"] } })
18. NOT IN
Employees not in those departments.
js
db.employees.find({ department: { $nin: ["Engineering", "IT"] } })
19. Check for Field Existence
Find documents where email field exists.
js
db.employees.find({ email: { $exists: true } })
Try it: 100 Python practice problems with solutions
20. Type Check
Find documents where salary is of type double (type 1).
js
db.employees.find({ salary: { $type: 1 } })
21. Regular Expression
Find employees whose name starts with “A”.
js
db.employees.find({ name: /^A/ })
22. Case‑insensitive Regex
Find employees with “eng” in the department name (case‑insensitive).
js
db.employees.find({ department: /eng/i })
23. Sorting Ascending
List employees ordered by salary ascending.
js
db.employees.find().sort({ salary: 1 })
24. Sorting Descending
Order by salary descending, then name ascending.
js
db.employees.find().sort({ salary: -1, name: 1 })
25. Limit Results
Get the top 3 highest‑paid employees.
js
db.employees.find().sort({ salary: -1 }).limit(3)
26. Skip
Skip the first 2 employees and return the next 2.
js
db.employees.find().skip(2).limit(2)
27. Count Documents
Count the number of employees in “Engineering”.
js
db.employees.countDocuments({ department: "Engineering" })
28. Distinct Values
Get all unique department names.
js
db.employees.distinct("department")
29. Update One Document
Increase Alice’s salary by 5000.
js
db.employees.updateOne({ name: "Alice" }, { $inc: { salary: 5000 } })
30. Update Many
Give all Engineering employees a 10% raise.
js
db.employees.updateMany(
{ department: "Engineering" },
{ $mul: { salary: 1.10 } }
)
31. Set a Field Value
Set a bonus field to 500 for HR employees.
js
db.employees.updateMany({ department: "HR" }, { $set: { bonus: 500 } })
32. Unset a Field
Remove the bonus field from all documents.
js
db.employees.updateMany({}, { $unset: { bonus: "" } })
33. Rename a Field
Rename name to fullName.
js
db.employees.updateMany({}, { $rename: { "name": "fullName" } })
34. Replace a Document
Replace Charlie’s entire document with a new one.
js
db.employees.replaceOne(
{ fullName: "Charlie" },
{ fullName: "Charlie", department: "Sales", salary: 70000, email: "charlie@example.com" }
)
35. Upsert
Update an employee with name “Diana” or insert if not found.
js
db.employees.updateOne(
{ name: "Diana" },
{ $set: { department: "Marketing", salary: 65000 } },
{ upsert: true }
)
36. Delete One Document
Delete the employee named “Bob”.
js
db.employees.deleteOne({ name: "Bob" })
37. Delete Many
Remove all employees with salary below 50000.
js
db.employees.deleteMany({ salary: { $lt: 50000 } })
38. Drop a Collection
Remove the products collection.
js
db.products.drop()
39. Create Index
Create an ascending index on salary.
js
db.employees.createIndex({ salary: 1 })
40. Compound Index
Create an index on department (ascending) and salary (descending).
js
db.employees.createIndex({ department: 1, salary: -1 })
41. Text Index
Create a text index on the name and department fields.
js
db.employees.createIndex({ name: "text", department: "text" })
42. Text Search
Search for documents containing “engineer” using the text index.
js
db.employees.find({ $text: { $search: "engineer" } })
43. Unique Index
Create a unique index on email field.
js
db.employees.createIndex({ email: 1 }, { unique: true })
44. View Indexes
List all indexes on the employees collection.
js
db.employees.getIndexes()
45. Drop an Index
Drop the index on salary.
js
db.employees.dropIndex("salary_1")
46. Aggregation: $match
Find employees with salary > 60000.
js
db.employees.aggregate([{ $match: { salary: { $gt: 60000 } } }])
47. Aggregation: $group
Count employees per department.
js
db.employees.aggregate([
{ $group: { _id: "$department", count: { $sum: 1 } } }
])
48. $group with Average
Compute average salary per department.
js
db.employees.aggregate([
{ $group: { _id: "$department", avgSalary: { $avg: "$salary" } } }
])
49. $project
Display name, department, and a computed field monthlySalary (salary / 12).
js
db.employees.aggregate([
{ $project: { name: 1, department: 1, monthlySalary: { $divide: ["$salary", 12] } } }
])
50. $sort in Aggregation
Sort departments by average salary descending.
js
db.employees.aggregate([
{ $group: { _id: "$department", avgSalary: { $avg: "$salary" } } },
{ $sort: { avgSalary: -1 } }
])
51. $limit in Aggregation
Return the top 2 highest salaries.
js
db.employees.aggregate([
{ $sort: { salary: -1 } },
{ $limit: 2 }
])
52. $unwind
Given a collection orders with an array field items, unwind it.
js
db.orders.aggregate([{ $unwind: "$items" }])
53. $unwind with preserveNullAndEmptyArrays
Unwind items keeping orders with empty or missing items.
js
db.orders.aggregate([{ $unwind: { path: "$items", preserveNullAndEmptyArrays: true } }])
54. $lookup (Join)
Join orders with customers on customerId.
js
db.orders.aggregate([
{ $lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
} }
])
55. $lookup with Pipeline
For each department, get the employees. (Reverse join)
js
db.departments.aggregate([
{ $lookup: {
from: "employees",
let: { dept: "$name" },
pipeline: [ { $match: { $expr: { $eq: ["$department", "$$dept"] } } } ],
as: "staff"
} }
])
56. $push to Create Array
Group employees per department and collect their names.
js
db.employees.aggregate([
{ $group: { _id: "$department", names: { $push: "$name" } } }
])
Try it: 100 Java practice problems with solutions
57. $addToSet
Collect unique salary values per department.
js
db.employees.aggregate([
{ $group: { _id: "$department", uniqueSalaries: { $addToSet: "$salary" } } }
])
58. $sum with Nested Field
Given orders with items array, compute total quantity sold per order.
js
db.orders.aggregate([
{ $addFields: { totalQty: { $sum: "$items.quantity" } } }
])
59. $bucket
Group employees into salary buckets: <50000, 50000‑100000, >=100000.
js
db.employees.aggregate([
{ $bucket: {
groupBy: "$salary",
boundaries: [0, 50000, 100000, Infinity],
default: "Other",
output: { count: { $sum: 1 } }
} }
])
60. $facet
Get in one aggregation: number of employees per department, and average salary per department.
js
db.employees.aggregate([
{ $facet: {
countPerDept: [{ $group: { _id: "$department", count: { $sum: 1 } } }],
avgSalaryPerDept: [{ $group: { _id: "$department", avg: { $avg: "$salary" } } }]
} }
])
61. $replaceRoot
Promote a nested document to top level.
js
db.orders.aggregate([
{ $lookup: { from: "customers", localField: "customerId", foreignField: "_id", as: "customer" } },
{ $unwind: "$customer" },
{ $replaceRoot: { newRoot: "$customer" } }
])
62. $merge
Write aggregation results into a new collection deptSummary.
js
db.employees.aggregate([
{ $group: { _id: "$department", avgSalary: { $avg: "$salary" } } },
{ $merge: { into: "deptSummary" } }
])
63. $out
Write aggregation results into a collection (overwrites if exists).
js
db.employees.aggregate([
{ $sort: { salary: -1 } },
{ $out: "sortedEmployees" }
])
64. $indexOfArray
Find the position of a value in an array.
js
db.orders.aggregate([
{ $project: { firstItemIndex: { $indexOfArray: ["$items.productId", "p123"] } } }
])
65. $filter
Filter array elements where quantity > 2.
js
db.orders.aggregate([
{ $project: { items: { $filter: { input: "$items", cond: { $gt: ["$$this.quantity", 2] } } } } }
])
66. Array $size
Add a field indicating the number of items in each order.
js
db.orders.aggregate([
{ $addFields: { itemCount: { $size: "$items" } } }
])
67. $slice
Return only the first 2 items from the items array.
js
db.orders.aggregate([{ $project: { firstTwo: { $slice: ["$items", 2] } } }])
68. $map over Array
For each order, create an array of item descriptions "quantity x product".
js
db.orders.aggregate([
{ $project: {
itemsDesc: { $map: {
input: "$items",
as: "item",
in: { $concat: [ { $toString: "$$item.quantity" }, " x ", "$$item.productId" ] }
} }
} }
])
69. $reduce
Compute total order value from items array (quantity * price) without using $sum.
js
db.orders.aggregate([
{ $project: {
total: {
$reduce: {
input: "$items",
initialValue: 0,
in: { $add: ["$$value", { $multiply: ["$$this.quantity", "$$this.price"] } ] }
}
}
} }
])
70. $cond
Create a field status: “High” if salary > 70000, else “Normal”.
js
db.employees.aggregate([
{ $addFields: { status: { $cond: { if: { $gt: ["$salary", 70000] }, then: "High", else: "Normal" } } } }
])
71. $switch
Categorize salary into “Low”, “Medium”, “High”.
js
db.employees.aggregate([
{ $addFields: {
category: {
$switch: {
branches: [
{ case: { $lt: ["$salary", 50000] }, then: "Low" },
{ case: { $lte: ["$salary", 100000] }, then: "Medium" }
],
default: "High"
}
}
} }
])
72. $dateToString
Format a date field hireDate as “YYYY‑MM‑DD”.
js
db.employees.aggregate([
{ $project: { hired: { $dateToString: { format: "%Y-%m-%d", date: "$hireDate" } } } }
])
73. year,month, $dayOfMonth
Extract year, month, day from orderDate.
js
db.orders.aggregate([
{ $project: { year: { $year: "$orderDate" }, month: { $month: "$orderDate" }, day: { $dayOfMonth: "$orderDate" } } }
])
74. groupwithfirst and $last
Get the first and last hired employee per department.
js
db.employees.aggregate([
{ $sort: { hireDate: 1 } },
{ $group: { _id: "$department", firstHired: { $first: "$name" }, lastHired: { $last: "$name" } } }
])
75. $currentDate
Set a lastModified field to the current date.
js
db.employees.updateMany({}, { $currentDate: { lastModified: true } })
76. minandmax in $group
Find min and max salary per department.
js
db.employees.aggregate([
{ $group: { _id: "$department", minSalary: { $min: "$salary" }, maxSalary: { $max: "$salary" } } }
])
77. $stdDevPop
Calculate standard deviation of salaries.
js
db.employees.aggregate([
{ $group: { _id: null, stdDev: { $stdDevPop: "$salary" } } }
])
78. sumwithConditional(sum and $cond)
Count the number of employees per department with salary > 70000.
js
db.employees.aggregate([
{ $group: { _id: "$department", highEarners: { $sum: { $cond: [ { $gt: ["$salary", 70000] }, 1, 0 ] } } } }
])
79. $round
Round salary to nearest thousand.
js
db.employees.aggregate([
{ $addFields: { roundedSalary: { $round: ["$salary", -3] } } }
])
80. $concat
Create full address string.
js
db.customers.aggregate([
{ $addFields: { fullAddress: { $concat: ["$city", ", ", "$country"] } } }
])
81. toUpper/toLower
Convert all names to uppercase in output.
js
db.employees.aggregate([{ $project: { name: { $toUpper: "$name" }, department: 1 } }])
82. $arrayElemAt
Get the second element from the items array.
js
db.orders.aggregate([{ $project: { secondItem: { $arrayElemAt: ["$items", 1] } } }])
83. $reverseArray
Reverse the items array.
js
db.orders.aggregate([{ $project: { reversedItems: { $reverseArray: "$items" } } }])
84. $in (aggregation operator)
Check if a value is in an array (different from query in).UseisArray? Actually there is $in expression that checks if a value is in an array.
js
db.employees.aggregate([
{ $addFields: { isEngineer: { $in: ["$department", ["Engineering", "IT"]] } } }
])
85. $objectToArray
Convert an object to an array of key‑value pairs.
js
db.customers.aggregate([{ $project: { asArray: { $objectToArray: "$address" } } }])
86. $arrayToObject
Convert an array of key‑value pairs to an object.
js
db.customers.aggregate([
{ $project: { addressObj: { $arrayToObject: "$addressFields" } } }
])
87. $setUnion
Union of two arrays.
js
db.orders.aggregate([
{ $project: { combinedCategories: { $setUnion: ["$categories", "$recommended"] } } }
])
88. $setIntersection
Intersection of arrays.
js
db.orders.aggregate([
{ $project: { common: { $setIntersection: ["$categories", "$recommended"] } } }
])
89. $setDifference
Items in array A not in B.
js
db.orders.aggregate([
{ $project: { missingRecs: { $setDifference: ["$categories", "$recommended"] } } }
])
90. $zip
Zip two arrays together.
js
db.orders.aggregate([
{ $project: { productQuantity: { $zip: { inputs: ["$productIds", "$quantities"] } } } }
])
91. Geospatial: 2dsphere Index
Create a 2dsphere index on location field.
js
db.places.createIndex({ location: "2dsphere" })
92. $near
Find places near a point (long, lat) within 1000 meters.
js
db.places.find({
location: {
$near: { $geometry: { type: "Point", coordinates: [ -73.97, 40.77 ] }, $maxDistance: 1000 }
}
})
93. $geoWithin
Find places within a specified polygon.
js
db.places.find({
location: { $geoWithin: { $geometry: { type: "Polygon", coordinates: [[...]] } } }
})
94. Transactions (with session)
Start a session and transfer money between accounts.
js
const session = db.getMongo().startSession();
session.startTransaction();
try {
db.accounts.updateOne({ _id: 1 }, { $inc: { balance: -100 } }, { session });
db.accounts.updateOne({ _id: 2 }, { $inc: { balance: 100 } }, { session });
session.commitTransaction();
} catch (error) {
session.abortTransaction();
} finally {
session.endSession();
}
95. BulkWrite
Perform multiple operations: insert, update, delete.
js
db.employees.bulkWrite([
{ insertOne: { document: { name: "Eve", department: "Finance", salary: 70000 } } },
{ updateOne: { filter: { name: "Alice" }, update: { $set: { salary: 65000 } } } },
{ deleteOne: { filter: { name: "Bob" } } }
])
96. Database Stats
Get statistics of the current database.
js
db.stats()
97. Collection Stats
Get storage size and document count of employees.
js
db.employees.stats()
Try it: 100 C++ practice problems with solutions
98. Explain
Explain a query plan for finding salary > 50000.
js
db.employees.find({ salary: { $gt: 50000 } }).explain("executionStats")
99. Create Capped Collection
Create a capped collection logs with a max size of 1 MB and max 1000 documents.
js
db.createCollection("logs", { capped: true, size: 1048576, max: 1000 })
100. Run Command (ping)
Ping the database to check connectivity.
js
db.runCommand({ ping: 1 })
Final Thought
One hundred problems ago, you were someone else.
Maybe a little timid, maybe aching to truly understand NoSQL, maybe craving the kind of mastery that feels almost out of reach. Today, you look back over a landscape of collections, aggregations, indexes, and pipelines — and something stirs inside you. A quiet longing for those early discovery days, when every $match and $group felt like unlocking a secret chamber. You’ll miss the late nights wrestling with a document that wouldn’t update, the gentle thrill when a complex query finally returned exactly what you desired. That sweet ache? It’s the signature of growth.
Now you’re standing on solid ground, but a new craving is already whispering — what else can I build? Let that desire pull you toward real-world projects, toward data you’ve never touched, toward the beautiful, messy, infinite world that only a developer’s heart can shape. Bookmark this page like a love letter to the learner you were — and open it again when nostalgia calls. Keep chasing that feeling.