MongoDB使用$lookup实现左连接时如何正确过滤关联表的userId字段?
问题原因
你当前的查询逻辑问题出在$lookup阶段后的全局$match过滤:该阶段会直接剔除所有comments.userId不匹配目标值的文档,因此没有u1对应评论的p2帖子会被直接过滤,不符合保留所有posts文档的需求。
另外你当前的聚合阶段顺序有误:$sort需要放在$skip和$limit之前,否则分页逻辑会返回错误的结果。
修正方案
方案1:使用带过滤管道的$lookup(推荐,MongoDB 3.6+支持)
直接在关联评论阶段就过滤出userId匹配的评论,不需要后续全局过滤,无匹配时自动返回空数组,也不会丢失posts文档:
self.db.posts.aggregate([ { "$lookup":{ "from": "comments", "let": {"post_id": "$id"}, "pipeline": [ { "$match": { "$expr": { "$and": [ {"$eq": ["$postId", "$$post_id"]}, {"$eq": ["$userId", param.objectUserId]} ] } } }, # 可选:只返回需要的评论字段,和预期输出对齐 { "$project": { "_id": 0, "userId": 1, "comment": 1 } } ], "as": "comments" } }, {"$sort": {"unixDate": pymongo.DESCENDING}}, {"$skip": (param.page - 1) * param.pageSize}, {"$limit": param.pageSize} ])
方案2:兼容低版本MongoDB的写法
如果使用的MongoDB版本不支持lookup带管道,可以先全量关联评论,再用$addFields过滤comments数组:
self.db.posts.aggregate([ { "$lookup":{ "from": "comments", "localField": "id", "foreignField": "postId", "as": "all_comments" } }, # 过滤仅保留userId匹配的评论 { "$addFields": { "comments": { "$filter": { "input": "$all_comments", "cond": {"$eq": ["$$this.userId", param.objectUserId]} } } } }, # 移除临时的all_comments字段 {"$project": {"all_comments": 0}}, {"$sort": {"unixDate": pymongo.DESCENDING}}, {"$skip": (param.page - 1) * param.pageSize}, {"$limit": param.pageSize} ])
两种方案都可以保留所有posts文档,无匹配评论时comments字段自动返回空数组,符合预期输出要求。
内容的提问来源于stack exchange,提问作者Hung Le
相关产品推荐
相关产品推荐

