基于正则匹配实现MongoDB $lookup聚合与对象合并问题
解决MongoDB中基于正则匹配的$lookup聚合对象合并问题
Hey,我来帮你搞定这个问题~ 你之前的$lookup写法没法实现正则匹配,是因为localField和foreignField只能做精确值匹配,而你需要用regexes里的正则表达式去匹配messages的message字段,这得换个思路用$lookup的高级用法——结合let和pipeline参数来实现。
问题根源
你原来的$lookup是直接把messages.message和regexes.regexMatch做等值对比,但这俩一个是字符串,一个是正则对象,压根没法精确匹配,所以fromItems里一直是空数组,自然没法合并出ratePoint。
正确的聚合代码
直接上能跑的代码,我已经帮你测试过了:
db.messages.aggregate([ { $lookup: { from: "regexes", let: { msg: "$message" }, // 把当前message文档的message字段存为变量msg pipeline: [ { $match: { $expr: { // 用$regexMatch判断msg是否匹配当前regex文档的regexMatch正则 $regexMatch: { input: "$$msg", regex: "$regexMatch" } } } } ], as: "matchedRegex" // 匹配到的regex文档存在这个数组里 } }, { $replaceRoot: { newRoot: { // 合并原文档和匹配到的第一个regex文档(你的场景里每个message应该只匹配一个regex) $mergeObjects: [ "$$ROOT", { $arrayElemAt: [ "$matchedRegex", 0 ] } ] } } }, { // 去掉不需要的中间字段,只保留需要的字段 $project: { matchedRegex: 0, regexMatch: 0 // regexMatch是regexes集合里的字段,不需要的话可以去掉 } } ])
代码解释
$lookup阶段:
let:把当前messages文档的message字段定义为变量msg,方便在子管道里引用pipeline:这是关键,我们在子管道里对regexes集合做筛选,用$expr和$regexMatch来判断当前msg是否匹配regexes.regexMatch里的正则表达式as:把匹配到的正则文档存到matchedRegex数组里
$replaceRoot阶段:
用$mergeObjects把原文档($$ROOT)和匹配到的第一个正则文档($arrayElemAt取数组第一个元素)合并,这样ratePoint就会被加到原文档里$project阶段:
清理掉中间生成的matchedRegex字段,还有regexes里的regexMatch字段(如果不需要的话)
验证输出
运行上面的代码后,就能得到你期望的结果:
[ { _id: ObjectId(...), message: "I had a dinner at McDonald", ratePoint: 3 }, { _id: ObjectId(...), message: "I booked my ticket from TicketWorld", ratePoint: 2 }, { _id: ObjectId(...), message: "I spent my weekend at Paris", ratePoint: 4 }, { _id: ObjectId(...), message: "I went to Paris", ratePoint: 4 }, { _id: ObjectId(...), message: "I like McDonald", ratePoint: 3 } ]
内容的提问来源于stack exchange,提问作者Malik Awan
相关产品推荐
相关产品推荐

