Episode 7 of 17

AND and OR Conditions

Master logical operators in MongoDB — $and, $or, $not, and $nor. Learn how to combine multiple conditions, build complex queries with nested logic, and understand implicit vs explicit AND operations.

Real-world queries rarely have just one condition. You'll often need to combine multiple filters — find users who are developers AND over 25, or products that are in electronics OR books categories. MongoDB provides four logical operators: $and, $or, $not, and $nor.

Implicit AND

When you pass multiple fields in a query filter, MongoDB treats them as AND conditions:

// Implicit AND — both conditions must be true
db.users.find({
    role: "developer",
    age: { $gt: 25 }
})
// Equivalent to: WHERE role = 'developer' AND age > 25

Explicit $and

Use $and when you need multiple conditions on the same field, or for clarity:

// Multiple conditions on the same field
db.products.find({
    $and: [
        { price: { $gte: 100 } },
        { price: { $lte: 500 } }
    ]
})
// Products priced between 100 and 500

// This is equivalent (and shorter):
db.products.find({
    price: { $gte: 100, $lte: 500 }
})

You MUST use explicit $and when you have multiple conditions with the same operator on the same field:

// Find products in "electronics" that are also NOT "refurbished"
db.products.find({
    $and: [
        { category: "electronics" },
        { category: { $ne: "refurbished" } }
    ]
})

$or — Match Any Condition

// Find developers OR designers
db.users.find({
    $or: [
        { role: "developer" },
        { role: "designer" }
    ]
})

// Note: For same-field "in" queries, $in is simpler:
db.users.find({ role: { $in: ["developer", "designer"] } })
// Find products that are cheap OR highly rated
db.products.find({
    $or: [
        { price: { $lt: 100 } },
        { rating: { $gte: 4.5 } }
    ]
})

Combining $and with $or

// Find active users who are either developers or designers
db.users.find({
    isActive: true,
    $or: [
        { role: "developer" },
        { role: "designer" }
    ]
})
// SQL: WHERE isActive = true AND (role = 'developer' OR role = 'designer')
// Complex: (category is electronics AND price > 500) OR (category is books AND rating > 4)
db.products.find({
    $or: [
        {
            $and: [
                { category: "electronics" },
                { price: { $gt: 500 } }
            ]
        },
        {
            $and: [
                { category: "books" },
                { rating: { $gt: 4 } }
            ]
        }
    ]
})

$not — Negate a Condition

// Find users whose age is NOT greater than 30
db.users.find({
    age: { $not: { $gt: 30 } }
})
// This matches age <= 30 AND documents without the age field

// Find names that do NOT start with "A"
db.users.find({
    name: { $not: /^A/ }
})

// $not vs $ne:
// $ne excludes a specific value
db.users.find({ role: { $ne: "admin" } })
// $not negates an entire expression
db.users.find({ age: { $not: { $gte: 18 } } })  // age < 18 or no age field

$nor — None of the Conditions

$nor returns documents that fail ALL specified conditions:

// Find users who are neither developers nor managers
db.users.find({
    $nor: [
        { role: "developer" },
        { role: "manager" }
    ]
})

// Find inactive users with no recent login
db.users.find({
    $nor: [
        { isActive: true },
        { lastLogin: { $gte: new Date("2024-01-01") } }
    ]
})

Real-World Examples

E-commerce Product Search

// Products in stock, priced 500-5000, in electronics or gadgets
db.products.find({
    inStock: true,
    price: { $gte: 500, $lte: 5000 },
    $or: [
        { category: "electronics" },
        { category: "gadgets" }
    ]
})

User Activity Report

// Users who are active AND (logged in this month OR have orders this month)
db.users.find({
    isActive: true,
    $or: [
        { lastLogin: { $gte: new Date("2024-12-01") } },
        { lastOrderDate: { $gte: new Date("2024-12-01") } }
    ]
})

Content Moderation

// Posts that are reported AND (have more than 5 reports OR are from banned users)
db.posts.find({
    isReported: true,
    $or: [
        { reportCount: { $gt: 5 } },
        { "author.isBanned": true }
    ]
})

Operator Summary

// $and — ALL conditions must match
// Implicit: { field1: val1, field2: val2 }
// Explicit: { $and: [ {cond1}, {cond2} ] }

// $or — ANY condition must match
// { $or: [ {cond1}, {cond2} ] }

// $not — Negates a single condition
// { field: { $not: { operator: value } } }

// $nor — NONE of the conditions must match
// { $nor: [ {cond1}, {cond2} ] }

What's Next

You can now build complex multi-condition queries. In the next episode, we'll learn how to update existing documents using updateOne(), updateMany(), and various update operators like $set, $inc, $push, and $pull.

TutorialMongoDBDatabaseNoSQL