【问题、AI解答】mongodb中使用$lookup进行连表查询使用_id作为localField出现查询结果字段为空的情况
描述:
db.acticles.aggregate([
{$lookup:{from:"acticlesMaptags",localField:"_id",foreignField:"acticleid",as:"tagid"}
}
])
acticlesMaptags集合中的acticleid字段存在与acticles集合中的_id相匹配的数据,但是查询出来的tagid却为空。
下面是acticles集合与acticlesMaptags集合:
{"RECORDS": [{"_id": "6436ba99e0180000d2007562","title": "这是标题","text": "这是内容","descripe": "接上期,MongoDB 的事务操作已经操作了,但细节和参数并没有弄清楚,通过mongodb 的事务操作主要分为以下几个部分1 Session.startTransaction2 ...","time": "1681308703868"},{"_id": "6436ba9de0180000d2007563","title": "这是标题","text": "这是内容","descripe": "事务是数据库中处理的逻辑单元,包括一个或多个数据库操作,既可以是读操作,也可以是写...要使用事务,你所部署的 MongoDB 必须是 MongoDB 4.2 或更高版本,MongoDB 的驱动程序必须更新为 MongoDB 4.2 或更高版本。...","time": "1681308703868"},{"_id": "6436c0dce0180000d200756c","title": "测试标题","text": "这是内容","descripe": "的哦奥球","time": "1681308703868"}]
}
{"RECORDS": [{"_id": "6436bfb9e0180000d200756a","acticleid": "6436ba99e0180000d2007562","tagid": "6436be71e0180000d2007565"},{"_id": "6436bff2e0180000d200756b","acticleid": "6436ba9de0180000d2007563","tagid": "6436bebae0180000d2007569"},{"_id": "6436c316e0180000d200756d","acticleid": "6436c0dce0180000d200756c","tagid": "6436be97e0180000d2007567"},{"_id": "6436c38ce0180000d200756e","acticleid": "6436c0dce0180000d200756c","tagid": "6436be97e0180000d2007567"},{"_id": "6438b4b0fe580000ec007ff2","acticleid": "6436ba9de0180000d2007563","tagid": "6436be97e0180000d2007567"}]
}
ai的回答:
根据您提供的文档,从逻辑上看 $lookup 查询语句是正确的,但是结果为空可能有以下几个可能性:
acticlesMaptags 集合中的 acticleid 字段中的值与 acticles 集合中的 _id 字段值不完全匹配。请注意确保两个集合之间使用相同类型的字段进行关联(例如,都使用 ObjectID 类型)。
如果您在执行 $lookup 查询时未指定相关的查询条件,则将从 acticlesMaptags 集合中检索所有与 acticles 集合中的文档匹配的记录,这可能会返回大量数据并导致查询超时或者无法查询出结果。 基于您的数据,这种情况似乎不太可能发生。
另外一个可能性是访问权限问题。请确保您有足够的权限访问 acticlesMaptags 集合。
我们建议你通过对 acticlesMaptags 进行简单的聚合查询来验证集合中是否存在与 acticles 集合中的 _id 字段匹配的文档。例如,可以执行以下查询:
db.acticlesMaptags.aggregate([{$match: {acticleid: {$in: db.acticles.distinct("_id")}},}
])
此查询将返回 acticlesMaptags 集合中与 acticles 集合中的 _id 字段匹配的文档。如果没有返回结果,则可能存在相关性或访问权限问题,您需要进一步进行排查。
解决
根据ai的回答我可以判断是类型不相同出现的问题,于是我还问了下ai的解决方案:
在MongoDB中,使用lookup可以实现表连接的操作。
lookup可以实现表连接的操作。lookup运算符可以将文档从一个集合连接到另一个集合,并将结果作为新的嵌入式文档数组返回。
如果要连接两个不同类型的字段(例如ObjectId和字符串),可以使用以下方式:
假设有两个集合:orders和customers。orders集合中包含一个名为customerId的ObjectId字段,而customers集合中包含一个名为_id的字符串字段。要在orders集合中查找所有订单,以及与之相关联的客户信息,请执行以下步骤:
db.orders.aggregate([{$lookup: {from: "customers",localField: "customerId",foreignField: "_id",as: "customer_info"}}
])
上述代码将在orders集合中查找所有订单,并将customer_info字段添加到每个订单文档中。该字段是一个由查询customers集合得到的包含客户信息的数组。其中localField指定了在orders集合中用于匹配的字段,而foreignField指定了在customers集合中用于匹配的字段。
需要注意的一点是,如果要连接的两个字段类型不同,则需要将localField字段的值写成一个对象,其中包含了类似 $toString 和 $toObjectId 等转换方法。例如,如果orders集合的customerId字段是一个字符串而非ObjectId,则可采用如下方式进行转换:
db.orders.aggregate([{$lookup: {from: "customers",localField: { $toObjectId: "$customerId" },foreignField: "_id",as: "customer_info"}}
])
上述代码将使用$toObjectId运算符将customerId字段从字符串转换为ObjectId。然后,它将在customers集合中查找与之匹配的文档,并将结果包含在customer_info字段中。
最终我的解决方案
添加一个转换为string类型的_id字段。
db.acticles.aggregate([{$addFields: {acticleid: { $toString: "$_id" }}},
{$lookup:{from:"acticlesMaptags",localField:"acticleid",foreignField:"acticleid",as:"tagid"}
}
])
成功!!!