如何让MongoDB聚合在$lookup失败时仍返回主记录?
解决MongoDB $lookup无匹配时保留主记录的问题
没问题!你遇到的情况是MongoDB默认的$unwind行为导致的:当$lookup在users集合里找不到匹配的文档时,users数组会是空的,而默认的$unwind会直接移除数组为空、null或者不存在的文档,所以你的主记录就被跳过了,后续的$project自然拿不到结果。
要实现“即使匹配失败仍返回主记录”,只需要给$unwind添加preserveNullAndEmptyArrays: true参数。这个参数会告诉MongoDB:就算目标数组是空的,也保留当前文档,此时users字段会被设为null。
下面是修改后的完整聚合代码:
db.booking.aggregate([ { '$match': { status: { '$in': [ 0, 1, 2, 3, 4, 5, 6, 9 ] }, '$or': [ { checkin: { '$gte': 1516320000 }, checkout: { '$lte': 1521417600 } }, { checkin: { '$lt': 1516320000 }, checkout: { '$gt': 1521417600 } }, { checkin: { '$lt': 1516320000 }, checkout: { '$gt': 1516320000 } }, { checkin: { '$lt': 1521417600 }, checkout: { '$gt': 1521417600 } } ] } }, { '$sort': { checkin: 1 } }, { '$lookup': { from: 'users', localField: 'user', foreignField: '_id', as: 'users' } }, // 关键修改:添加preserveNullAndEmptyArrays参数 { '$unwind': { path: '$users', preserveNullAndEmptyArrays: true } }, { '$project': { _id: 1, property: 1, user: 1, // 可选:用$ifNull给无匹配的字段设置默认值,避免返回null name: { '$ifNull': ['$users.name', '未知用户'] }, country: { '$ifNull': ['$users.country', '未知国家'] }, checkin: 1, checkout: 1, priceNight: 1, status: 1, source: 1 } } ], {})
额外提示:
- 这个特性要求MongoDB版本在3.2及以上,如果你用的是更早的版本,可能需要考虑升级或者用其他方式(比如先判断数组是否为空再处理,但显然加参数是最简洁的方案)。
- 如果不需要默认值,直接写
name: '$users.name'也可以,此时没有匹配到用户的记录里,name和country会是null,你可以根据业务需求选择。
内容的提问来源于stack exchange,提问作者torbenrudgaard
相关产品推荐
相关产品推荐

