数组查询
本教程共 50 篇 · 第 17 篇 · 更新于 2026-07-30 · 约 8 分钟阅读
17. 数组查询
本节目标:掌握针对数组字段的查询——怎么匹配「包含全部」「按条件匹配某个元素」「按长度」以及「不含某些值」。
17.1 准备带数组的数据
本章用 users 的 tags 数组,以及新建 orders(商品明细是文档数组)来演示。先建 orders:
db.orders.insertMany([
{
_id: 1001,
user_id: 1,
items: [
{ product: "键盘", qty: 1, price: 199 },
{ product: "鼠标", qty: 2, price: 89 }
],
total: 377,
status: "paid",
created_at: ISODate("2024-01-20")
},
{
_id: 1002,
user_id: 2,
items: [
{ product: "显示器", qty: 1, price: 1299 }
],
total: 1299,
status: "pending",
created_at: ISODate("2024-02-11")
},
{
_id: 1003,
user_id: 1,
items: [
{ product: "键盘", qty: 3, price: 199 }
],
total: 597,
status: "paid",
created_at: ISODate("2024-03-05")
}
])
users 沿用第 13 章那 5 条,外加第 16 章为演示 $exists 插入的第 6 条(其 tags 为 ["new"])。
17.2 隐式包含匹配
最基础的:数组字段直接写值,表示「数组里包含这个值即可」:
// tags 数组里包含 "vip" 的用户(不论位置)
db.users.find({ tags: "vip" }).pretty()
这条会命中张伟、王芳、陈强。
17.3 $all:包含全部元素
$all 要求数组同时含有列表里的每一个值:
// tags 同时包含 vip 和 gamer
db.users.find({ tags: { $all: ["vip", "gamer"] } }).pretty()
只有张伟的 tags 是 ["vip", "gamer"],所以只命中他。
Tip
$all不要求顺序,也不要求只有这些。只要「都有」就匹配。
17.4 $size:按数组长度匹配
$size 按数组元素个数筛选:
// tags 恰好只有 1 个元素
db.users.find({ tags: { $size: 1 } }).pretty()
示例里李娜 ["new"]、陈强 ["vip"]、刘洋 ["gamer"],以及第 16 章那条 ["new"] 都是长度 1,会命中。
Warning
$size不能配合范围运算符(如$gt)直接用。想查「长度大于 1」,得另建一个记录长度的字段,或用聚合阶段$expr配合$size表达式。
17.5 $elemMatch:按条件匹配数组元素
当数组里是文档,且要「同一个元素满足多个条件」时,用 $elemMatch:
// items 里存在某个元素:product 是键盘 且 qty > 1
db.orders.find({
items: {
$elemMatch: { product: "键盘", qty: { $gt: 1 } }
}
}).pretty()
只有 1003 号订单的键盘 qty: 3 满足,所以命中它。
Note据 MongoDB 8.3 官方文档,
$elemMatch保证多个条件落在「同一个数组元素」上;若分别写{ "items.product": "键盘", "items.qty": { $gt: 1 } },则可能跨不同元素满足,结果不同。
17.6 $nin:数组不含某些值
$nin 用在数组字段上时,表示「数组里不出现列表中的任何一个值」:
// tags 数组里不含 "vip"
db.users.find({ tags: { $nin: ["vip"] } }).pretty()
这会命中那些 tags 里没有 vip 的用户(如李娜、刘洋,以及第 16 章那条 ["new"] 的用户)。
17.7 小结
数组查询记住四把刷子:
- 直接写值:数组含该元素即可。
$all:必须含全部指定元素。$size:按元素个数匹配。$elemMatch:数组元素是文档时,约束「同一元素」满足多条件。