如何编写MongoDB聚合查询筛选匹配系统的合适会话?
MongoDB聚合查询实现匹配系统需求
需求描述
用户"TARGET"发起匹配请求,需通过MongoDB聚合查询完成以下逻辑:
- 从
sessions集合中筛选出所有type: "TEXT"且status: "WAITING"的会话文档 - 对每个筛选出的文档,检查该文档
members[0]对应的用户与"TARGET"是否在集合内任意文档的members数组中共同出现过(即是否有过匹配记录) - 排除曾匹配过的会话,返回最终符合条件的会话列表
示例数据
sessions集合的示例文档如下:
[ { "status": "WAITING", "type": "TEXT", "members": [ "adam" ] }, { "status": "WAITING", "type": "TEXT", "members": [ "john" ] }, { "status": "WAITING", "type": "VOICE", "members": [ "alex" ] }, { "status": "ENDED", "type": "VOICE", "members": [ "adam", "alex" ] }, { "status": "TIMEOUT", "type": "TEXT", "members": [ "adam", "TARGET" ] } ]
期望返回结果
[ { "status": "WAITING", "type": "TEXT", "members": [ "john" ] } ]
结果说明
集合中共有3个WAITING状态的会话:
- adam的会话:TARGET曾与adam在
TIMEOUT状态的会话中匹配过,因此排除 - alex的会话:类型为
VOICE,不符合TEXT类型要求,因此排除 - john的会话:既符合类型和状态要求,且与TARGET无匹配记录,因此保留
聚合查询实现
以下是满足需求的MongoDB聚合管道:
db.sessions.aggregate([ // 第一步:筛选出TEXT类型、WAITING状态的会话 { $match: { type: "TEXT", status: "WAITING" } }, // 第二步:为每个候选会话关联所有包含TARGET的会话,检查是否与当前用户有共同匹配记录 { $lookup: { from: "sessions", let: { candidateUser: { $arrayElemAt: ["$members", 0] } }, pipeline: [ { $match: { $expr: { $and: [ { $in: ["TARGET", "$members"] }, { $in: ["$$candidateUser", "$members"] } ] } } } ], as: "matchedHistory" } }, // 第三步:排除有匹配历史的会话(matchedHistory为空数组表示无匹配记录) { $match: { matchedHistory: { $size: 0 } } }, // 第四步:移除临时字段matchedHistory,保留原会话结构 { $project: { matchedHistory: 0 } } ])
管道逻辑说明
- $match:先过滤出符合基础条件的等待会话
- $lookup:针对每个候选会话的用户,查询集合中同时包含该用户和TARGET的所有会话,将结果存入
matchedHistory数组 - $match:只保留
matchedHistory为空的会话(即无匹配记录) - $project:移除查询过程中生成的临时字段,返回原始会话结构
参考JS代码
原需求的JS实现逻辑(供对照参考):
let waiting = findSessions() // 常规查询获取status为"WAITING"的会话 let results = []; for (let w of waiting) { // 仅当w.members[0]与TARGET_USER_ID从未匹配过时,才加入结果 // 即集合中不存在同时包含这两个ID的文档 if (!hasMatchedBefore(w.members[0], "TARGET_USER_ID")) { results.push(w); } }
内容的提问来源于stack exchange,提问作者haste
相关产品推荐
相关产品推荐

