MongoDB单文档多层嵌套数组内属性的唯一性校验配置方法
MongoDB单文档多层嵌套数组内属性的唯一性校验配置方法
嗨,我完全懂你踩的坑了——直接用$rows.blocks.id会把所有嵌套层级里的id都拉成一个一维数组,这时候你校验的是整个文档里所有row下的blocks.id全局唯一,而不是你真正需要的「每个row内部的blocks.id不能重复」,这就是为什么你的配置没拦住非法文档的原因。
咱们得换个思路:要逐个检查每个rows元素里的blocks.id数组,确保每个单独的row都满足唯一性,最后再确认所有row都通过校验。具体的配置逻辑是这样的:
- 用
$map遍历文档里的每一个rows元素 - 对每个row,用你之前知道的
$size和$setUnion的对比方法,检查这个row下的blocks.id有没有重复 - 用
$allElementsTrue确保所有row的校验结果都是true,这样整个文档才符合要求
给你直接能用的完整命令:
db.runCommand({ collMod: "你的集合名称", validator: { $expr: { $allElementsTrue: { $map: { input: "$rows", in: { $eq: [ { $size: "$$this.blocks.id" }, { $size: { $setUnion: "$$this.blocks.id" } } ] } } } } }, // 可选配置,建议加上确保校验生效 validationLevel: "strict", validationAction: "error" })
我给你拆解下关键部分:
$$this在$map里代表当前遍历到的那个rows元素(也就是单个row),所以$$this.blocks.id只会取这个row下的所有blocks的id数组,不会跨row$allElementsTrue会检查$map返回的布尔数组里是不是全是true,只要有一个row的blocks.id有重复,整个表达式就会返回false,validator就会阻止文档写入
你可以测试一下:比如插入一个包含rows: [{id: "r1", blocks: [{id: "b1"}, {id: "b1"}]}]的文档,这个配置会直接拦住它;而合法的文档(每个row里的blocks.id都不重复)就能正常写入。
内容来源于stack exchange
相关产品推荐
相关产品推荐

