文档的查询(find、findOne)
查询基础
MongoDB提供了find()
和findOne()
两个核心方法用于文档查询。find()
返回匹配查询条件的所有文档,而findOne()
只返回第一个匹配的文档。两者都接受查询条件作为参数,如果不提供参数则返回集合中的所有文档(对于find()
)或第一个文档(对于findOne()
)。
// 查找所有用户
db.users.find()
// 查找第一个用户
db.users.findOne()
// 查找年龄为25的用户
db.users.find({ age: 25 })
// 查找第一个年龄为25的用户
db.users.findOne({ age: 25 })
查询条件
查询条件使用JSON格式指定,可以包含各种比较操作符和逻辑操作符。基本查询条件直接使用字段和值的匹配:
// 精确匹配
db.products.find({ category: "electronics" })
// 使用比较操作符
db.products.find({ price: { $gt: 100 } }) // 价格大于100
常用比较操作符包括:
$eq
:等于$ne
:不等于$gt
:大于$gte
:大于等于$lt
:小于$lte
:小于等于$in
:在数组中$nin
:不在数组中
逻辑操作符
MongoDB提供了逻辑操作符来组合多个查询条件:
// AND操作(隐式)
db.users.find({ age: 25, status: "active" })
// AND操作(显式)
db.users.find({ $and: [{ age: 25 }, { status: "active" }] })
// OR操作
db.users.find({ $or: [{ age: 25 }, { status: "active" }] })
// NOT操作
db.users.find({ age: { $not: { $gt: 30 } } })
查询嵌套文档
对于嵌套文档,可以使用点表示法查询:
// 查询address.city为"New York"的用户
db.users.find({ "address.city": "New York" })
// 查询嵌套数组中的元素
db.users.find({ "hobbies": "reading" })
// 使用$elemMatch查询数组中的复合条件
db.users.find({
scores: {
$elemMatch: {
type: "exam",
score: { $gt: 90 }
}
}
})
投影(字段选择)
find()
和findOne()
的第二个参数用于指定返回哪些字段(投影):
// 只返回name和email字段
db.users.find({}, { name: 1, email: 1 })
// 排除_id字段
db.users.find({}, { _id: 0, name: 1, email: 1 })
// 排除status字段
db.users.find({}, { status: 0 })
查询数组
数组查询有几种特殊操作符:
// 精确匹配整个数组
db.users.find({ tags: ["red", "blue"] })
// 匹配数组中的任意元素
db.users.find({ tags: "red" })
// 使用$all匹配包含所有指定元素的数组
db.users.find({ tags: { $all: ["red", "blue"] } })
// 使用$size匹配特定长度的数组
db.users.find({ tags: { $size: 3 } })
分页和排序
结合limit()
、skip()
和sort()
方法可以实现分页查询:
// 第一页,每页10条,按创建时间降序
db.users.find()
.sort({ createdAt: -1 })
.limit(10)
.skip(0)
// 第二页
db.users.find()
.sort({ createdAt: -1 })
.limit(10)
.skip(10)
性能考虑
查询性能受多种因素影响:
- 索引:确保查询字段有适当的索引
- 投影:只返回必要的字段
- 查询选择性:高选择性的查询(返回少量文档)性能更好
- 避免全集合扫描:使用
explain()
分析查询计划
// 分析查询
db.users.find({ age: 25 }).explain("executionStats")
聚合查询
虽然find()
和findOne()
适合简单查询,复杂的数据处理可以使用聚合框架:
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
])
文本搜索
MongoDB支持文本索引和搜索:
// 创建文本索引
db.articles.createIndex({ title: "text", content: "text" })
// 文本搜索
db.articles.find({ $text: { $search: "mongodb tutorial" } })
地理空间查询
对于包含地理空间数据的文档,可以使用特殊查询操作符:
// 查找距离某点1000米内的地点
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [longitude, latitude]
},
$maxDistance: 1000
}
}
})
查询优化技巧
- 使用覆盖查询(查询只使用索引中的字段)
- 避免使用
$where
(JavaScript表达式性能较差) - 合理使用
hint()
强制使用特定索引 - 监控慢查询日志
// 强制使用特定索引
db.users.find({ age: 25 }).hint({ age: 1 })
事务中的查询
在MongoDB事务中,查询行为与普通查询类似,但需要考虑隔离级别:
session.startTransaction()
try {
const user = db.users.findOne({ _id: userId }, { session })
// 处理逻辑
session.commitTransaction()
} catch (error) {
session.abortTransaction()
}
批量查询操作
对于大量数据,可以使用批量查询方法提高效率:
// 批量查找多个ID
db.users.find({ _id: { $in: [id1, id2, id3] } })
// 使用游标处理大量数据
const cursor = db.users.find()
while (cursor.hasNext()) {
const doc = cursor.next()
// 处理文档
}
查询与复制集
在复制集环境中,可以指定读取偏好:
// 从主节点读取(默认)
db.users.find().readPref("primary")
// 从次节点读取
db.users.find().readPref("secondary")
// 从最近的节点读取
db.users.find().readPref("nearest")
查询与分片集群
在分片集群中,查询会被路由到相应的分片:
// 当查询包含分片键时,可以直接路由到特定分片
db.orders.find({ customerId: "123" }) // 假设customerId是分片键
// 不包含分片键的查询会广播到所有分片(性能较差)
db.orders.find({ status: "pending" })
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn