如何在MongoDB中筛选描述不含集合A文本的集合B文档?
如何在MongoDB中实现指定的过滤逻辑
嘿,这个需求我熟!对应你那串Plain JS的filter+some逻辑,MongoDB里有两种常用的实现方式,我给你掰扯清楚~
方法一:客户端先获取匹配值再查询(适合集合A数据量小的场景)
这种方式和你写的JS逻辑思路最接近:先把集合A里所有data字段的值捞出来,再用这个列表去过滤集合B。
步骤1:获取集合A的所有data值
// 先查询集合A,提取所有不重复的data值 const dataList = await db.collectionA.distinct("data"); // 此时dataList会是 ["demon", "god"]
步骤2:构造正则表达式过滤集合B
把dataList里的值拼接成正则,用$not来反向匹配——也就是只保留description里不包含任何A中data值的文档:
// 构造正则(加"i"是忽略大小写,不需要可以去掉) const excludeRegex = new RegExp(dataList.join("|"), "i"); // 查询集合B const result = await db.collectionB.find({ description: { $not: excludeRegex } }).toArray();
执行后就能得到Book C这个符合要求的文档。
方法二:用聚合管道全程在数据库端处理(更灵活,适合大数据量)
如果不想在客户端做中间处理,或者集合A的数据量比较大,可以用MongoDB的聚合管道直接在数据库端完成整个逻辑:
db.collectionB.aggregate([ // 第一步:关联集合A,把所有data值捞出来放到aData字段里 { $lookup: { from: "collectionA", pipeline: [{ $project: { data: 1, _id: 0 } }], // 只取data字段,减少数据传输 as: "aData" } }, // 第二步:判断当前文档的description是否包含aData里的任意值 { $addFields: { hasMatch: { $anyElementTrue: { $map: { input: "$aData", // 用$regexMatch判断是否包含(MongoDB 4.2+支持) in: { $regexMatch: { input: "$description", regex: "$$this.data" } } } } } } }, // 第三步:只保留没有匹配到的文档 { $match: { hasMatch: false } }, // 第四步:清理掉不需要的中间字段 { $project: { aData: 0, hasMatch: 0 } } ])
兼容低版本MongoDB的写法
如果你的MongoDB版本低于4.2(不支持$regexMatch),可以把$map里的判断换成$indexOfCP:
in: { $ne: [{ $indexOfCP: ["$description", "$$this.data"] }, -1] }
$indexOfCP会返回子串的位置,返回-1就说明不包含,用$ne判断是否不等于-1,也就是是否包含。
两种方法的适用场景
- 方法一:代码更简洁,执行速度快,但依赖客户端处理,适合集合A数据量小的情况。
- 方法二:全程在数据库端执行,不需要客户端做中间处理,适合集合A数据量大,或者需要把逻辑封装在数据库层的场景。
内容的提问来源于stack exchange,提问作者Autumn's Fall
相关产品推荐
相关产品推荐

