MongoDB高级查询 #

一、复杂条件查询 #

1.1 嵌套条件 #

javascript
// 嵌套文档查询
db.users.find({
    "address.city": "Beijing",
    "address.zipCode": "100000"
})

// 嵌套数组查询
db.orders.find({
    "items.productId": ObjectId("..."),
    "items.quantity": { $gt: 1 }
})

1.2 多层嵌套 #

javascript
// 多层嵌套查询
db.companies.find({
    "headquarters.address.city": "Shanghai",
    "headquarters.address.country": "China"
})

// 嵌套数组中的对象
db.users.find({
    "education.school": "MIT",
    "education.degree": "Bachelor"
})

1.3 复杂逻辑组合 #

javascript
// 复杂逻辑组合
db.users.find({
    $and: [
        {
            $or: [
                { status: "active" },
                { status: "pending" }
            ]
        },
        {
            $or: [
                { age: { $lt: 18 } },
                { age: { $gt: 60 } }
            ]
        }
    ]
})

// 使用$expr进行字段间比较
db.products.find({
    $expr: { $gt: ["$price", "$cost"] }
})

// 使用$expr进行复杂计算
db.orders.find({
    $expr: {
        $gt: [
            { $multiply: ["$quantity", "$price"] },
            1000
        ]
    }
})

二、数组高级查询 #

2.1 数组元素匹配 #

javascript
// $elemMatch精确匹配数组元素
db.users.find({
    scores: {
        $elemMatch: {
            subject: "math",
            score: { $gte: 80, $lte: 100 }
        }
    }
})

// 多条件元素匹配
db.orders.find({
    items: {
        $elemMatch: {
            productId: ObjectId("..."),
            quantity: { $gt: 1 },
            price: { $lt: 100 }
        }
    }
})

2.2 数组索引查询 #

javascript
// 按索引查询数组元素
db.users.find({ "hobbies.0": "reading" })

// 按索引查询嵌套对象
db.users.find({ "scores.0.subject": "math" })

2.3 数组长度查询 #

javascript
// 查询数组长度
db.users.find({ hobbies: { $size: 3 } })

// 查询数组长度范围(使用$expr)
db.users.find({
    $expr: { $gt: [{ $size: "$hobbies" }, 2] }
})

2.4 数组包含查询 #

javascript
// 包含所有元素
db.users.find({
    hobbies: { $all: ["reading", "swimming", "coding"] }
})

// 包含任意元素(使用$in)
db.users.find({
    hobbies: { $in: ["reading", "swimming"] }
})

2.5 数组元素更新位置操作符 #

javascript
// 查询时使用$定位操作符
db.users.find(
    { "scores.subject": "math" },
    { "scores.$": 1 }
)

// 更新时使用$定位操作符
db.users.updateOne(
    { "scores.subject": "math" },
    { $set: { "scores.$.score": 95 } }
)

三、正则表达式查询 #

3.1 基本正则查询 #

javascript
// 正则表达式查询
db.users.find({ name: /^John/ })

// 不区分大小写
db.users.find({ name: /^john/i })

// 使用$regex操作符
db.users.find({
    name: { $regex: /^john/, $options: "i" }
})

3.2 正则选项 #

javascript
// 正则选项
db.users.find({
    name: {
        $regex: "john",
        $options: "imxs"
    }
})

// 选项说明:
// i - 不区分大小写
// m - 多行匹配
// x - 忽略空白
// s - 点号匹配所有字符

3.3 复杂正则查询 #

javascript
// 邮箱格式验证
db.users.find({
    email: {
        $regex: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
    }
})

// 手机号验证
db.users.find({
    phone: {
        $regex: /^1[3-9]\d{9}$/
    }
})

// IP地址验证
db.logs.find({
    ip: {
        $regex: /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/
    }
})

3.4 正则与索引 #

javascript
// 创建文本索引支持正则查询
db.users.createIndex({ name: "text" })

// 使用文本索引查询
db.users.find({ $text: { $search: "John" } })

// 前缀匹配可以使用索引
db.users.find({ name: /^John/ })  // 可以使用索引

// 非前缀匹配不能使用索引
db.users.find({ name: /John/ })   // 不能使用索引

四、文本搜索 #

4.1 创建文本索引 #

javascript
// 创建文本索引
db.articles.createIndex({ title: "text", content: "text" })

// 创建复合文本索引
db.articles.createIndex({
    title: "text",
    content: "text"
}, {
    weights: {
        title: 10,
        content: 5
    },
    default_language: "none"
})

4.2 基本文本搜索 #

javascript
// 文本搜索
db.articles.find({ $text: { $search: "MongoDB" } })

// 多词搜索(OR)
db.articles.find({ $text: { $search: "MongoDB database" } })

// 短语搜索
db.articles.find({ $text: { $search: "\"MongoDB database\"" } })

// 排除词
db.articles.find({ $text: { $search: "MongoDB -MySQL" } })

4.3 文本搜索排序 #

javascript
// 按相关性排序
db.articles.find(
    { $text: { $search: "MongoDB" } },
    { score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })

4.4 文本搜索选项 #

javascript
// 文本搜索选项
db.articles.find(
    { $text: { $search: "MongoDB", $language: "en", $caseSensitive: false } },
    { score: { $meta: "textScore" } }
)

五、地理位置查询 #

5.1 地理索引 #

javascript
// 创建2dsphere索引
db.places.createIndex({ location: "2dsphere" })

// 创建2d索引
db.places.createIndex({ location: "2d" })

// 创建复合地理索引
db.places.createIndex({ location: "2dsphere", category: 1 })

5.2 地理位置数据格式 #

javascript
// GeoJSON格式
{
    location: {
        type: "Point",
        coordinates: [116.4074, 39.9042]  // [经度, 纬度]
    }
}

// LineString
{
    location: {
        type: "LineString",
        coordinates: [[116.4074, 39.9042], [121.4737, 31.2304]]
    }
}

// Polygon
{
    location: {
        type: "Polygon",
        coordinates: [[[116.4074, 39.9042], [121.4737, 31.2304], [113.2644, 23.1291], [116.4074, 39.9042]]]
    }
}

5.3 附近查询 #

javascript
// 查找附近的点
db.places.find({
    location: {
        $near: {
            $geometry: {
                type: "Point",
                coordinates: [116.4074, 39.9042]
            },
            $maxDistance: 1000,  // 最大距离(米)
            $minDistance: 10     // 最小距离(米)
        }
    }
})

// 使用$nearSphere(球面距离)
db.places.find({
    location: {
        $nearSphere: {
            $geometry: {
                type: "Point",
                coordinates: [116.4074, 39.9042]
            },
            $maxDistance: 1000
        }
    }
})

5.4 范围查询 #

javascript
// 在多边形范围内查询
db.places.find({
    location: {
        $geoWithin: {
            $geometry: {
                type: "Polygon",
                coordinates: [[[116.4074, 39.9042], [121.4737, 31.2304], [113.2644, 23.1291], [116.4074, 39.9042]]]
            }
        }
    }
})

// 在圆形范围内查询
db.places.find({
    location: {
        $geoWithin: {
            $center: [[116.4074, 39.9042], 10]  // [中心点, 半径(弧度)]
        }
    }
})

// 在球面圆形范围内查询
db.places.find({
    location: {
        $geoWithin: {
            $centerSphere: [[116.4074, 39.9042], 10 / 6378.1]  // [中心点, 半径(弧度)]
        }
    }
})

5.5 相交查询 #

javascript
// 查找相交的几何图形
db.places.find({
    location: {
        $geoIntersects: {
            $geometry: {
                type: "Polygon",
                coordinates: [[[116.4074, 39.9042], [121.4737, 31.2304], [113.2644, 23.1291], [116.4074, 39.9042]]]
            }
        }
    }
})

5.6 地理聚合 #

javascript
// 计算距离
db.places.aggregate([
    {
        $geoNear: {
            near: {
                type: "Point",
                coordinates: [116.4074, 39.9042]
            },
            distanceField: "distance",
            maxDistance: 10000,
            spherical: true
        }
    }
])

六、日期查询 #

6.1 日期范围查询 #

javascript
// 日期范围查询
db.events.find({
    createdAt: {
        $gte: ISODate("2024-01-01"),
        $lt: ISODate("2025-01-01")
    }
})

// 最近N天
db.events.find({
    createdAt: {
        $gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
    }
})

6.2 日期聚合查询 #

javascript
// 按日期分组
db.events.aggregate([
    {
        $group: {
            _id: {
                year: { $year: "$createdAt" },
                month: { $month: "$createdAt" },
                day: { $dayOfMonth: "$createdAt" }
            },
            count: { $sum: 1 }
        }
    }
])

// 按小时分组
db.events.aggregate([
    {
        $group: {
            _id: {
                year: { $year: "$createdAt" },
                month: { $month: "$createdAt" },
                day: { $dayOfMonth: "$createdAt" },
                hour: { $hour: "$createdAt" }
            },
            count: { $sum: 1 }
        }
    }
])

七、null和存在性查询 #

7.1 null值查询 #

javascript
// 查询null值
db.users.find({ middleName: null })

// 注意:这会匹配null值和不存在的字段

// 只匹配null值
db.users.find({ middleName: { $type: 10 } })

// 只匹配字段不存在
db.users.find({ middleName: { $exists: false } })

7.2 存在性查询 #

javascript
// 字段存在
db.users.find({ email: { $exists: true } })

// 字段不存在
db.users.find({ email: { $exists: false } })

// 字段存在且不为null
db.users.find({
    email: {
        $exists: true,
        $ne: null
    }
})

八、查询优化技巧 #

8.1 使用索引 #

javascript
// 创建合适的索引
db.users.createIndex({ email: 1 })
db.users.createIndex({ "address.city": 1, age: -1 })

// 使用hint强制索引
db.users.find({ email: "john@example.com" }).hint({ email: 1 })

8.2 限制结果 #

javascript
// 使用limit
db.users.find().limit(100)

// 使用投影
db.users.find({}, { name: 1, email: 1 })

8.3 避免全表扫描 #

javascript
// 不推荐:使用$where
db.users.find({ $where: "this.age > 20" })

// 推荐:使用操作符
db.users.find({ age: { $gt: 20 } })

// 不推荐:使用函数
db.users.find({ $expr: { $gt: [{ $function: { body: function(age) { return age * 2; }, args: ["$age"], lang: "js" }}, 40] } })

// 推荐:使用聚合表达式
db.users.find({ $expr: { $gt: [{ $multiply: ["$age", 2] }, 40] } })

8.4 查询分析 #

javascript
// 查看执行计划
db.users.find({ age: { $gt: 20 } }).explain("executionStats")

// 关注指标:
// - totalDocsExamined:扫描的文档数
// - totalKeysExamined:扫描的索引键数
// - executionTimeMillis:执行时间
// - indexUsed:使用的索引

九、总结 #

高级查询操作符:

操作符 说明
$elemMatch 数组元素匹配
$all 包含所有元素
$size 数组长度
$regex 正则表达式
$text 文本搜索
$near 附近查询
$geoWithin 范围查询
$geoIntersects 相交查询
$expr 表达式查询

下一步,让我们学习聚合管道!

最后更新:2026-03-27