FerretDB 数组查询操作符实战指南:$all、$elemMatch 与 $size 的用法与源码解析
FerretDB 数组查询操作符实战指南$all、$elemMatch 与 $size 的用法与源码解析【免费下载链接】FerretDBA truly Open Source MongoDB alternative项目地址: https://gitcode.com/gh_mirrors/fe/FerretDB本文以 FerretDB 仓库的官方文档 array-operators.md 为核心骨架系统讲解三个数组查询操作符$all、$elemMatch、$size的语法、语义与实战示例。FerretDB 是一个开源的 MongoDB 替代品项目描述为 A truly Open Source MongoDB alternative其查询语义与 MongoDB 高度兼容。读完本文你将掌握如何通过这三个操作符精准筛选数组字段并理解 FerretDB 中与之对应的兼容性测试与实现边界可直接在自己的查询中复用文中的命令。操作符总览数组查询操作符用于在文档的数组字段中搜索特定元素。FerretDB 官方文档列出了以下三个核心操作符操作符描述$all选择包含查询中给出的全部元素的数组$elemMatch筛选数组中存在满足所有列出的查询条件的特定元素的文档$size根据给定的元素个数选择数组从语义上看三者分别解决三类问题$all关心数组里是否包含一组值$elemMatch关心数组中是否存在一个同时满足多重条件的元素$size关心数组的长度是否精确等于某个值。它们常被用于标签系统、技能列表、多值属性等典型数组字段的筛选场景。准备测试数据官方文档以team集合为例先写入四条包含skills数组字段的员工文档。在 FerretDB 中执行同样的insertMany即可准备测试环境db.team.insertMany([ { id: 1, name: Jack Smith, position: Manager, skills: [leadership, communication, project management], contact: { email: johnexample.com, phone: 123-456-7890 }, active: true }, { id: 2, name: Jane Mark, position: Software Developer, skills: [Java, Python, C], contact: { email: janeexample.com, phone: 123-456-7891 }, active: false }, { id: 3, name: Bob Johnson, position: Graphic Designer, skills: [Adobe Photoshop, Illustrator, InDesign], contact: { email: bobexample.com, phone: 123-456-7892 }, active: true }, { id: 4, name: Alice Williams, position: Marketing Coordinator, skills: [communication, content creation, event planning], contact: { email: aliceexample.com, phone: 123-456-7893 }, active: true } ])下文所有示例均基于这四条文档展开便于对照验证。$all匹配包含全部指定元素的数组语法{ field: { $all: [ element1, element2, ... elementN ] } }当需要选出数组中同时包含给定列表中每一个元素的文档时使用$all操作符。注意使用$all时数组中元素的顺序与数组长度无关紧要只要数组包含查询中的所有元素即可命中。示例在team集合中查找skills字段同时包含communication和content creation两个元素的文档db.team.find({ skills: { $all: [communication, content creation] } })输出结果response [ { _id: ObjectId(63a5bb4acf72d6203bb45bb5), id: 4, name: Alice Williams, position: Marketing Coordinator, skills: [communication, content creation, event planning], contact: { email: aliceexample.com, phone: 123-456-7893 }, active: true } ]只有 Alice 的skills数组[communication, content creation, event planning]同时包含这两个元素因此命中。$all 的边界情况与兼容性测试$all的语义细节可以通过 FerretDB 的兼容性测试源码得到印证。integration/query_array_compat_test.go 中的TestQueryArrayCompatAll覆盖了如下典型场景空数组查询$all: []返回空结果EmptyResult即空数组要求不匹配任何数组重复元素$all: [foo, foo, foo]与单个foo等价重复不改变命中结果如StringRepeated、WholeTwoRepeated用例所示多类型混合$all: [foo, 42]要求数组同时包含字符串与数值两种类型MultiAllWithNil还验证了包含null元素的场景非数组参数$all: 1或$all: null不会被当作合法数组条件返回空结果$allNeedsAnArrayInt、$allNeedsAnArrayNil用例浮点边界math.MaxFloat64、math.SmallestNonzeroFloat64等极端数值均可正常参与匹配DoubleMax、DoubleMin用例。这些用例通过testQueryCompat驱动同时运行于 FerretDB 与真实的 MongoDB 之上做结果对比从侧面说明了 FerretDB 对$all语义的兼容性是有测试保障的。$elemMatch匹配满足多重条件的数组元素语法{ field: { $elemMatch: { condition1, condition2, ... conditionN } } }当需要筛选出数组中至少存在一个元素同时满足 $elemMatch 内列出的所有查询条件的文档时使用$elemMatch。与$all的跨元素取交集不同$elemMatch要求所有条件作用在同一个数组元素上这是它最核心的语义区别。示例查找team集合中skills数组包含元素Java、且数组不包含元素communication的文档db.team.find({ skills: { $elemMatch: { $eq: Java, $nin: [communication] } } })输出结果response [ { _id: ObjectId(63aa247e69c82de72bd40b93), id: 2, name: Jane Mark, position: Software Developer, skills: [Java, Python, C], contact: { email: janeexample.com, phone: 123-456-7891 }, active: false } ]Jane 的skills数组中存在元素Java满足$eq同时整个数组没有communication满足$nin因此命中。注意第 4 条文档 Alice 虽含communication但没有任何一个元素等于Java两条条件无法在同一元素上同时成立故不命中。$elemMatch 的边界情况与兼容性测试同一测试文件中的TestQueryArrayCompatElemMatch揭示了更多细节多重比较条件作用于同一元素$elemMatch: { $gt: 0, $lt: 43 }要求数组中存在一个元素同时大于 0 且小于 43混合其他操作符$elemMatch可与$type等操作符并列使用如$elemMatch: {$gt: 0}与$type: array组合此时不同条件可以作用于数组的不同元素参数类型约束$elemMatch: foo这类非文档参数会被拒绝并返回空结果UnexpectedFilterString用例不支持的操作符嵌套$where、$text不允许出现在$elemMatch内部相关用例WhereInsideElemMatch、TextInsideElemMatch期望返回空结果。这些用例同样采用 MongoDB 对比测试的方式确保 FerretDB 在$elemMatch行为上与 MongoDB 保持一致。$size按数组长度精确匹配语法{ field: { $size: number-of-elements } }$size用于精确选择数组元素个数等于指定数值的文档适合按数组长度做筛选的场景。示例选择team集合中skills数组恰好包含三个元素的文档db.team.find({ skills: { $size: 3 } })输出结果response [ { _id: ObjectId(63aa247e69c82de72bd40b92), id: 1, name: Jack Smith, position: Manager, skills: [leadership, communication, project management], contact: { email: johnexample.com, phone: 123-456-7890 }, active: true }, { _id: ObjectId(63aa247e69c82de72bd40b93), id: 2, name: Jane Mark, position: Software Developer, skills: [Java, Python, C], contact: { email: janeexample.com, phone: 123-456-7891 }, active: false }, { _id: ObjectId(63aa247e69c82de72bd40b94), id: 3, name: Bob Johnson, position: Graphic Designer, skills: [Adobe Photoshop, Illustrator, InDesign], contact: { email: bobexample.com, phone: 123-456-7892 }, active: true }, { _id: ObjectId(63aa247e69c82de72bd40b95), id: 4, name: Alice Williams, position: Marketing Coordinator, skills: [communication, content creation, event planning], contact: { email: aliceexample.com, phone: 123-456-7893 }, active: true } ]四条文档的skills数组长度都是 3因此全部命中。$size 的边界情况与兼容性测试TestQueryArrayCompatSize对$size的约束覆盖得很完整数值类型宽容float64(2)、int32(2)、int64(2)三种数值类型写法均可正常匹配非整数与负数$size: 2.1NotWhole、$size: -1Negative均为非法输入返回空结果零长度$size: 0可以匹配空数组Zero用例不存在的字段字段缺失视为不匹配NotFound用例错误用法$size直接作用于顶层{$size: 2}或传入文档条件$size: {$gt: 1}都返回空结果InvalidUse、InvalidType用例。值得注意的一个已知差异$size: Infinity在 FerretDB 中暂时与 MongoDB 行为不一致failsForFerretDB标记指向了 FerretDB-DocumentDB 的 issue #245实际使用时应避免传入非有限数值。数组查询的补充知识与点号表示法的配合除了上述三个专用操作符数组查询还常与点号表示法dot notation结合。在 integration/query_array_compat_test.go 的TestQueryArrayCompatDotNotation中可以看到v.0、v.array.0、v[0]、v[*]等写法均可用于定位数组的特定位置例如{ v.array.0: { $gte: 42 } }会匹配数组首元素大于等于 42 的文档。文档 comparison-operators.md 中的$eq、$gt、$in、$nin等操作符也常与数组字段组合使用作为$elemMatch内部条件的补充手段。在 FerretDB 中如何验证查询FerretDB 的集成测试框架提供了验证数组查询行为的现成入口位于 integration 目录下的query_array_compat_test.go以表驱动的方式testQueryCompat将同一组过滤器同时发送给 FerretDB 与 MongoDB逐一对比结果query_array_test.go 则针对已知错误消息与行为差异做定向验证。如果你在 FerretDB 上编写数组查询可以参考这两个文件确认预期行为例如正则作为数组位置谓词时 MongoDB 会返回BadValue错误。小结$all、$elemMatch、$size三个数组查询操作符覆盖了包含全部元素存在满足复合条件的单个元素长度精确匹配三类常见筛选需求。在 FerretDB 中它们的语义不仅有官方文档背书更有 query_array_compat_test.go 中与 MongoDB 逐条对比的兼容性测试作为实现保障。实际开发中建议优先用$all表达包含关系、用$elemMatch表达同一元素上的复合条件、用$size做精确长度过滤并避开$size传入非有限值等已知边界差异。更多数组相关操作符可参考 array-update-operators.md如$push、$addToSet等更新操作符。【免费下载链接】FerretDBA truly Open Source MongoDB alternative项目地址: https://gitcode.com/gh_mirrors/fe/FerretDB创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考