1. BASIC CRUD (Create, Read, Update, Delete)

Category Command Description
Create Model.create(data) Insert a new document
  new Model(data).save() Create and save manually
Read Model.find() Get all documents
  Model.findOne(filter) Get one document that matches filter
  Model.findById(id) Get document by its _id
  Model.find(filter, projection) Filter and select specific fields
Update Model.updateOne(filter, update) Update the first matching document
  Model.updateMany(filter, update) Update multiple documents
  Model.findByIdAndUpdate(id, update, options) Update by ID and optionally return updated doc
Delete Model.deleteOne(filter) Delete first matching document
  Model.deleteMany(filter) Delete multiple documents
  Model.findByIdAndDelete(id) Delete by ID

Examples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// User
[
  {
    "_id": "652a12c4d12e1a2b5f8f3d9a",
    "name": "Alice",
    "email": "alice@example.com",
    "age": 25,
    "status": "active",
    "role": "user",
    "createdAt": "2025-09-15T10:30:00Z"
  },
  {
    "_id": "652a12c4d12e1a2b5f8f3d9b",
    "name": "Bob",
    "email": "bob@example.com",
    "age": 30,
    "status": "inactive",
    "role": "admin",
    "createdAt": "2025-08-12T09:45:00Z"
  },
  {
    "_id": "652a12c4d12e1a2b5f8f3d9c",
    "name": "Charlie",
    "email": "charlie@example.com",
    "age": 35,
    "status": "active",
    "role": "manager",
    "createdAt": "2025-07-22T14:15:00Z"
  },
  {
    "_id": "652a12c4d12e1a2b5f8f3d9d",
    "name": "Diana",
    "email": "diana@example.com",
    "age": 28,
    "status": "inactive",
    "role": "user",
    "createdAt": "2025-06-01T12:00:00Z"
  },
  {
    "_id": "652a12c4d12e1a2b5f8f3d9e",
    "name": "Ethan",
    "email": "ethan@example.com",
    "age": 40,
    "status": "active",
    "role": "superadmin",
    "createdAt": "2025-05-18T16:45:00Z"
  }
]
  1. CREATE
1
2
3
4
5
6
// Example 1: Simple create
await User.create({ name: "Alice", age: 25 });

// Example 2: Using constructor + save
const user = new User({ name: "Bob", age: 30 });
await user.save();

The first method inserts directly; the second creates an instance, allowing you to run pre-save hooks or validations before saving.

  1. READ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Example 1: Get all users
const users = await User.find();

// Example 2: Find by filter
const activeUsers = await User.find({ status: "active" });

// Example 3: Find one specific user
const user = await User.findOne({ email: "test@gmail.com" });

// Example 4: Find by ID
const user = await User.findById("652a12c4d12e1a2b5f8f3d9c");

// Example 5: Filter and select fields
const names = await User.find({}, "name email");
  1. UPDATE
1
2
3
4
5
6
7
8
9
10
11
12
// Example 1: Update one
await User.updateOne({ name: "Alice" }, { $set: { age: 26 } });

// Example 2: Update many
await User.updateMany({ status: "inactive" }, { $set: { status: "active" } });

// Example 3: Update by ID and return the new version
const updatedUser = await User.findByIdAndUpdate(
  "652a12c4d12e1a2b5f8f3d9c",
  { $set: { age: 35 } },
  { new: true }
);
  1. DELETE
1
2
3
4
5
6
7
8
// Example 1: Delete one
await User.deleteOne({ name: "Alice" });

// Example 2: Delete many
await User.deleteMany({ status: "inactive" });

// Example 3: Delete by ID
await User.findByIdAndDelete("652a12c4d12e1a2b5f8f3d9c");

2. COMMON QUERY PATTERNS

Purpose Example Description
Get all Model.find({}) Fetch everything
Filter Model.find({ age: 20 }) Match certain fields
Comparison { age: { $gt: 18 } }, { age: { $lte: 30 } } $gt, $lt, $gte, $lte
Multiple conditions { $and: [{ age: 20 }, { active: true }] } Combine conditions
Value in list { age: { $in: [18, 20, 25] } } $in, $nin
Fuzzy search { name: { $regex: 'john', $options: 'i' } } Case-insensitive search
Check existence { email: { $exists: true } } Field existence
Null check { field: null } Match null fields

Examples:

  1. Get all

Fetch every document in the users collection.

1
const users = await User.find({});

Returns all documents in the collection, equivalent to SELECT * FROM users in SQL.

  1. Filter

Find users who are exactly 20 years old.

1
const youngUsers = await User.find({ age: 20 });

Matches documents with age = 20.

  1. Comparison Operators

Find users older than 18 and younger or equal to 30.

1
const result = await User.find({ age: { $gt: 18, $lte: 30 } });

$gt = greater than, $lte = less than or equal.

  1. Multiple Conditions

Find users who are 20 years old and active.

1
const users = await User.find({ $and: [{ age: 20 }, { status: 'active' }] });

$and combines multiple filters; $or works similarly for alternatives.

  1. Value in List

Find users whose age is either 18, 20, or 25.

1
const users = await User.find({ age: { $in: [18, 20, 25] } });

$in checks for membership; $nin is the opposite (not in list).

  1. Regex (Regular Expression)

Find users whose name contains “john”, case-insensitive.

1
const users = await User.find({ name: { $regex: 'john', $options: 'i' } });

$regex supports pattern matching like SQL LIKE ‘%john%’.

  1. Check Existence

Find users who have an email field defined.

1
const users = await User.find({ email: { $exists: true } });

$exists returns documents whether a field is present or not.

  1. Null Check

Find users where the field nickname is null.

1
const users = await User.find({ nickname: null });

Matches documents where nickname is null or not defined.

3. MONGODB OPERATORS

Type Operators Meaning
Comparison $eq, $ne, $gt, $gte, $lt, $lte Equals, not equals, greater/less than
Logical $and, $or, $nor, $not Combine logic conditions
Array $in, $nin, $all, $size Match array values
Update $set, $inc, $push, $pull, $addToSet, $unset Modify data
Check $exists, $type Check if field exists or its type
  1. Comparison

Used in queries to filter by specific values or ranges.

1
2
3
4
5
6
7
8
9
10
11
// Equal to 25
await User.find({ age: { $eq: 25 } });

// Not equal to 'inactive'
await User.find({ status: { $ne: 'inactive' } });

// Greater than or equal to 30
await User.find({ age: { $gte: 30 } });

// Less than 40
await User.find({ age: { $lt: 40 } });

These operators are used for direct value comparisons — equivalent to SQL’s =, !=, >, <, >=, <=.

  1. Logical

Used to combine or negate multiple filter conditions.

1
2
3
4
5
6
7
8
// Match users who are active AND older than 25
await User.find({ $and: [{ status: 'active' }, { age: { $gt: 25 } }] });

// Match users who are either admin OR manager
await User.find({ $or: [{ role: 'admin' }, { role: 'manager' }] });

// Match users who are NOT active
await User.find({ status: { $not: { $eq: 'active' } } });

$and, $or, $not, $nor help you build complex query logic.

  1. Array Operators

Used when working with arrays inside documents.

1
2
3
4
5
6
7
8
// Match if 'skills' contains at least one of these values
await User.find({ skills: { $in: ['NodeJS', 'React'] } });

// Match if 'skills' includes ALL listed values
await User.find({ skills: { $all: ['MongoDB', 'Express'] } });

// Match arrays with exactly 3 items
await User.find({ skills: { $size: 3 } });

$in and $nin check membership; $all checks that all specified values are present; $size checks array length.

  1. Update Operators

Used in updateOne(), updateMany(), or findByIdAndUpdate() to modify data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Set a new field value
await User.updateOne({ name: 'Alice' }, { $set: { status: 'active' } });

// Increment a number field
await User.updateOne({ name: 'Bob' }, { $inc: { age: 1 } });

// Add an item to an array
await User.updateOne({ name: 'Charlie' }, { $push: { skills: 'Docker' } });

// Remove an item from an array
await User.updateOne({ name: 'Charlie' }, { $pull: { skills: 'React' } });

// Add only if not already in array
await User.updateOne({ name: 'Ethan' }, { $addToSet: { skills: 'AI' } });

// Remove a field completely
await User.updateOne({ name: 'Diana' }, { $unset: { nickname: "" } });

hese are essential for updating documents without overwriting the entire object.

  1. Check Operators

Used to inspect whether a field exists or to verify its type.

1
2
3
4
5
// Find documents that have an 'email' field
await User.find({ email: { $exists: true } });

// Find where 'age' is stored as a Number
await User.find({ age: { $type: 'number' } });

4. LIMIT, SORT, PAGINATION

Feature Example Description
Limit .limit(10) Limit number of results
Skip .skip(20) Skip first N results
Sort .sort({ age: 1 }) 1 = ascending, -1 = descending
Select fields .select('name age') Include only certain fields
Exclude fields .select('-password -email') Exclude specific fields

Examples

  1. Limit results

Retrieve only the first 10 users from the database.

1
const users = await User.find().limit(10);

Used for efficiency — prevents returning too many records at once.

  1. Skip results

Skip the first 20 users and return the rest.

1
const users = await User.find().skip(20);

Commonly used in pagination systems to “jump” to a later set of results.

  1. Sort results

Sort users by age in ascending or descending order.

1
2
3
4
5
// Ascending (youngest first)
const ascUsers = await User.find().sort({ age: 1 });

// Descending (oldest first)
const descUsers = await User.find().sort({ age: -1 });

You can also sort by multiple fields:

1
await User.find().sort({ status: 1, age: -1 });
  1. Skip results

Retrieve only specific fields like name and age.

1
const users = await User.find().select('name age');
  1. Exclude fields

Hide sensitive or unnecessary data such as passwords or emails.

1
const users = await User.find().select('-password -email');

The minus sign (-) means “exclude this field” — useful for security.

  1. Combine for pagination

Typical pagination query example:

1
2
3
4
5
6
7
8
const page = 2;
const limit = 5;
const skip = (page - 1) * limit;

const users = await User.find()
  .sort({ createdAt: -1 })
  .skip(skip)
  .limit(limit);

This retrieves page 2, with 5 users per page, sorted by newest creation date.

5. POPULATE (JOIN BETWEEN COLLECTIONS)

1
const posts = await Post.find().populate('author', 'name email');
Command Description
.populate('refField') Fetch referenced document
.populate('refField', 'name age') Fetch only selected fields
.populate({ path: 'author', match: { active: true } }) Apply filter inside populate

Examples:

JSON Plus for Posts collections:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[
  {
    "_id": "700a12c4d12e1a2b5f8f3aaa",
    "title": "AI in Business",
    "content": "Using AI to optimize workflows.",
    "author": "652a12c4d12e1a2b5f8f3d9a",
    "likes": 45,
    "tags": ["AI", "Business"],
    "createdAt": "2025-09-16T09:00:00Z"
  },
  {
    "_id": "700a12c4d12e1a2b5f8f3aab",
    "title": "Managing Teams Effectively",
    "content": "Leadership strategies for modern managers.",
    "author": "652a12c4d12e1a2b5f8f3d9c",
    "likes": 23,
    "tags": ["Leadership", "HR"],
    "createdAt": "2025-09-20T14:30:00Z"
  },
  {
    "_id": "700a12c4d12e1a2b5f8f3aac",
    "title": "System Architecture",
    "content": "Designing scalable NodeJS backends.",
    "author": "652a12c4d12e1a2b5f8f3d9b",
    "likes": 58,
    "tags": ["Tech", "Backend"],
    "createdAt": "2025-09-25T10:00:00Z"
  }
]
  1. Basic populate (simple JOIN)

Fetch all posts and include full author details.

1
const posts = await Post.find().populate('author');

Output:

1
2
3
4
5
6
7
8
9
10
[
  {
    "title": "AI in Business",
    "author": { "name": "Alice", "email": "alice@example.com", "role": "user" }
  },
  {
    "title": "System Architecture",
    "author": { "name": "Bob", "email": "bob@example.com", "role": "admin" }
  }
]
  1. Populate only specific fields

Fetch only the author’s name and email.

1
const posts = await Post.find().populate('author', 'name email');

Output:

1
2
3
4
5
6
[
  {
    "title": "AI in Business",
    "author": { "name": "Alice", "email": "alice@example.com" }
  }
]
  1. Populate with filter (match condition)

Only populate authors whose status is “active”.

1
2
3
4
5
const posts = await Post.find().populate({
  path: 'author',
  match: { status: 'active' },
  select: 'name email status'
});

Output:

1
2
3
4
5
6
7
8
9
10
[
  {
    "title": "AI in Business",
    "author": { "name": "Alice", "email": "alice@example.com", "status": "active" }
  },
  {
    "title": "System Architecture",
    "author": null // Bob was filtered out (inactive)
  }
]
  1. Nested populate (populate inside populate)

Assume there’s another collection Comment that references both Post and User:

1
2
3
4
5
6
const Comment = mongoose.model('Comment', new mongoose.Schema({
  post: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' },
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  content: String,
  createdAt: Date
}));

Now fetch all comments, including both:

1
2
3
4
5
6
const comments = await Comment.find()
  .populate({
    path: 'post',
    populate: { path: 'author', select: 'name email' }
  })
  .populate('user', 'name');

Output:

1
2
3
4
5
6
7
8
9
10
[
  {
    "content": "Great article!",
    "user": { "name": "Diana" },
    "post": {
      "title": "AI in Business",
      "author": { "name": "Alice", "email": "alice@example.com" }
    }
  }
]
  1. Populate multiple references at once

If your Post schema had both author and reviewer, you can populate both in one query:

1
2
3
const posts = await Post.find()
  .populate('author', 'name')
  .populate('reviewer', 'name');

6. AGGREGATION PIPELINE

Stage Example Description
$match { $match: { active: true } } Filter documents
$group { $group: { _id: '$status', count: { $sum: 1 } } } Group and count
$sort { $sort: { age: -1 } } Sort results
$project { $project: { name: 1, age: 1 } } Select fields
$lookup Lookup another collection (JOIN)  
$unwind Deconstruct an array field  

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const result = await User.aggregate([
  { $match: { status: 'active' } },
  { $lookup: {
      from: 'posts',
      localField: '_id',
      foreignField: 'author',
      as: 'posts'
  }},
  { $unwind: '$posts' },
  { $group: {
      _id: '$name',
      totalPosts: { $sum: 1 },
      avgLikes: { $avg: '$posts.likes' }
  }},
  { $sort: { totalPosts: -1 } }
]);

7. COUNT & EXISTENCE CHECKS

Command Description
countDocuments(filter) Count documents that match filter
estimatedDocumentCount() Fast count of all documents
exists(filter) Returns true/false if document exists

Examples:

1
2
3
4
5
6
7
8
9
10
// Count all active users
const activeCount = await User.countDocuments({ status: 'active' });

// Get total number of users quickly
const totalCount = await User.estimatedDocumentCount();

// Check if a user with a given email exists
const isExisting = await User.exists({ email: 'alice@example.com' });

console.log({ activeCount, totalCount, isExisting });

8. COMBINED ADVANCED QUERY EXAMPLE

Get a list of active users along with their posts, show only selected fields, compute total posts and average likes per user, then sort by total posts (descending).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const result = await User.aggregate([
  // 1. Filter only active users
  { 
    $match: { status: 'active' } 
  },

  // 2. Join with Post collection (JOIN equivalent)
  { 
    $lookup: {
      from: 'posts',
      localField: '_id',
      foreignField: 'author',
      as: 'posts'
    } 
  },

  // 3. Add computed fields (totalPosts, avgLikes)
  { 
    $addFields: {
      totalPosts: { $size: '$posts' },
      avgLikes: { $avg: '$posts.likes' }
    } 
  },

  // 4. Project only desired fields
  { 
    $project: { 
      name: 1, 
      email: 1, 
      totalPosts: 1, 
      avgLikes: { $round: ['$avgLikes', 1] } 
    } 
  },
  // 5. Sort descending
  { 
    $sort: { totalPosts: -1 } 
  }
]);