MongoDB 3.2使用$nin时ObjectId数组不被识别问题求助
解决MongoDB 3.2中匹配未关联的订阅文档问题
咱们先把需求捋清楚:要找出那些存在device属性,并且自身_id没有出现在对应devices文档的订阅数组里的subscriptions文档。结合MongoDB 3.2的特性,咱们可以用聚合管道来一步步实现:
具体聚合步骤
先过滤规范的订阅文档
第一步先把数据库里不规范、没有device字段的订阅文档筛掉,同时确保device是合法的ObjectId类型,避免后续关联出错:{ $match: { device: { $exists: true, $type: "objectId" } } }关联对应的设备文档
用$lookup把每个订阅对应的设备文档拉取过来(因为是一对多关系,每个订阅只会匹配到一个设备),这一步会给订阅文档新增一个matched_device数组,里面是匹配到的设备数据:{ $lookup: { from: "devices", localField: "device", foreignField: "_id", as: "matched_device" } }展开数组并筛选未关联的订阅
先用$unwind把matched_device数组展开成单个文档,方便后续字段对比;接着用$match筛选出自身_id不在设备订阅数组里的文档:{ $unwind: "$matched_device" }, { $match: { $expr: { $not: { $in: [ "$_id", "$matched_device.subscriptions" ] } } } }这里
$expr是MongoDB 3.2支持的语法,允许在查询条件里直接引用文档的字段值,刚好满足咱们对比两个字段的需求。可选:精简返回字段
如果不需要返回所有字段,可以用$project只保留你关心的内容,比如:{ $project: { _id: 1, device: 1, // 其他你需要的字段 } }
完整聚合查询
把上面的阶段组合起来,完整的查询语句如下:
db.subscriptions.aggregate([ { $match: { device: { $exists: true, $type: "objectId" } } }, { $lookup: { from: "devices", localField: "device", foreignField: "_id", as: "matched_device" } }, { $unwind: "$matched_device" }, { $match: { $expr: { $not: { $in: [ "$_id", "$matched_device.subscriptions" ] } } } }, // 可选的投影阶段 { $project: { _id: 1, device: 1 } } ])
额外注意点
- 如果有些订阅的
device指向的设备文档不存在,matched_device会是空数组,$unwind会自动过滤掉这类文档;如果想保留这类订阅,可以在$unwind里加上preserveNullAndEmptyArrays: true,再后续判断matched_device是否为空。 - 因为是MongoDB 3.2版本,
$lookup只支持基础的等值关联,不过刚好能满足咱们的需求。
内容的提问来源于stack exchange,提问作者Theocat
相关产品推荐
相关产品推荐

