数组查询怎么下手
数组字段的查询分几种形态:直接写等值表示「任一元素等于它」,$all 要求全部包含,$size 限定精确长度,$elemMatch 要求同一条元素同时满足多个条件。分清这几种语义是写好数组查询的前提,也是实践中最容易出错的地方。
基本信息
| 命中任一元素 | { tags: "mongo" } |
|---|---|
| 全部包含 | $all: ["mongo", "index"] |
| 精确长度 | $size: 3,不能与其他条件共用同一字段 |
| 同元素组合 | $elemMatch: { $gt: 80, $lt: 90 } |
| 索引行为 | 数组字段上的索引是多键索引,$elemMatch 更利于收敛范围 |
典型使用场景
- 标签筛选:命中包含某个标签的文档
- 多重条件:要求同时具备若干标签
- 区间判定:分数数组里存在落在某区间的元素
- 长度过滤:找出元素数量不符合预期的脏数据
- 嵌套数组:数组里存子文档时按子字段过滤
常用写法
常用写法
// 命中任一元素
db.posts.find({ tags: "mongo" })
// 要求全部包含
db.posts.find({ tags: { $all: ["mongo", "index"] } })
// 数组内存在落在 80 到 90 之间的元素
db.posts.find({ scores: { $elemMatch: { $gt: 80, $lt: 90 } } })
// 精确长度过滤:元素个数为 3
db.posts.find({ tags: { $size: 3 } })
// 嵌套子文档:按子字段过滤,组合条件用 $elemMatch
db.orders.find({ "items.sku": "A-1" })
db.orders.find({ items: { $elemMatch: { sku: "A-1", qty: { $gt: 2 } } } })写法与语义
| 写法 | 语义 | 常见误用 |
|---|---|---|
| { tags: "mongo" } | 任一元素等于该值 | 当成要求所有元素都等于它 |
| $all | 必须包含列出的全部值 | 顺序无关,但每个值都要存在 |
| $size: 3 | 元素数量精确等于 3 | 与其他条件共用同一字段时不生效 |
| $elemMatch | 同一条元素满足全部条件 | 不写时会变成不同元素各自满足 |
$size 不能与其他条件共用同一个字段表达式,精确长度判断只能单独写;需要长度加其他条件并存时,用聚合管道或预先落一个长度字段。
对数组子文档做组合条件时优先用 $elemMatch:它把条件约束在同一条元素上,与「数组字段加点号」的宽松语义完全不同。