MongoDb:使用 $lookup 查找深度嵌套的对象
Posted
技术标签:
【中文标题】MongoDb:使用 $lookup 查找深度嵌套的对象【英文标题】:MongoDb: find deeply nested object with $lookup 【发布时间】:2020-07-21 08:47:01 【问题描述】:我有这样的收藏: 集合名称是 - 帐户。 它有子文档,例如帐户 > 建筑物 > 网关 > 设备。
"_id" : ObjectId("5e1fe45cd05bfb0cc549297d"),
"apiCallCount" : 0,
"email" : "info@data.com",
"password" : "dummy",
"userName" : "AAAAA",
"companyName" : "The AAAAAA",
"apiKey" : "5e1fe45cd05bfb0cc549297c",
"solutionType" : "VVVVVV",
"parentCompany" : "",
"buildings" : [
"_id" : ObjectId("5e1fe5e3d05bfb0cc5494146"),
"buildingName" : "xxxxxx",
"address" : "xxx",
"suite" : "101",
"floor" : "22",
"timeZone" : "us/eastern",
"gateways" : [
"_id" : ObjectId("5e1fe624d05bfb0cc549453a"),
"gatewayName" : "CC-GW-THF-001",
"gatewayKey" : "gk_5e1fe624d05bfb0cc549453a",
"suite" : "area1",
"devices" : [
"_id" : ObjectId("5e1fe751d05bfb0cc549578d"),
"serialNumber" : "129300000013",
"area" : "area1",
"connectionStatus" : 1,
"gatewayKey" : "gk_5e1fe624d05bfb0cc549453a",
"applicationNumber" : 30,
"firmwareVersion" : "1.0",
"needsAttention" : false,
"verificationCode" : "GAAS",
"createdAt" : ISODate("2020-01-16T04:32:17.899Z"),
"updatedAt" : ISODate("2020-01-16T08:53:54.460Z")
],
"createdAt" : ISODate("2020-01-16T04:27:16.678Z"),
"updatedAt" : ISODate("2020-01-16T08:53:54.460Z")
,
"_id" : ObjectId("5e1fe651d05bfb0cc54947f0"),
"gatewayName" : "AA-GW-THF-002",
"gatewayKey" : "gk_5e1fe651d05bfb0cc54947f0",
"suite" : "area2",
"devices" : [
"_id" : ObjectId("5e1fe7a9d05bfb0cc5495cdf"),
"serialNumber" : "129300000012",
"area" : "area2",
"connectionStatus" : 0,
"gatewayKey" : "gk_5e1fe651d05bfb0cc54947f0",
"applicationNumber" : 30,
"firmwareVersion" : "1.0",
"needsAttention" : false,
"verificationCode" : "VG3K",
"createdAt" : ISODate("2020-01-16T04:33:45.698Z"),
"updatedAt" : ISODate("2020-01-16T08:54:17.604Z")
],
"createdAt" : ISODate("2020-01-16T04:28:01.532Z"),
"updatedAt" : ISODate("2020-01-16T08:54:17.604Z")
,
],
"createdAt" : ISODate("2020-01-16T04:26:11.941Z"),
"updatedAt" : ISODate("2020-01-16T08:56:32.657Z")
],
"createdAt" : ISODate("2020-01-16T04:19:40.310Z"),
"updatedAt" : ISODate("2020-04-06T18:18:39.628Z"),
"__v" : 1,
我有 accountId、buildingId、gatewayId、deviceId。 我正在尝试使用 $lookup 运算符查找匹配的设备对象。
我想我必须先使用 buildingId 找到建筑物对象,然后使用 gatewayId 过滤该建筑物下的网关,然后使用我拥有的 deviceId 找到设备对象。
我基本上需要访问设备对象字段才能在最终输出中进行投影。 难以为使用查找运算符提出正确的管道。
到目前为止我有这个:
db.getCollection('test').aggregate([
$lookup:
from: 'account',
let:
accountId: "$accountId"
,
pipeline: [
"$match":
"$expr":
"$eq": ["$_id", "$$accountId"]
,
],
as: "accountDetails"
,
$unwind: "$accountDetails"
,
$lookup:
from: 'account',
let:
accountId: "$accountId",
buildingId: "$buildingId",
buildings: "$accountDetails"
,
pipeline: [
"$match":
"$expr":
"$eq": ["$buildings._id", "$$buildingId"] // how to dig through nested document to get to devices ?
,
],
as: "buildingDetails"
$project: ... ...
])
如果我这样做:
$lookup:
from: 'account',
localField: "accountId",
foreignField: "_id",
as: "accountDetails"
,
accountDetails 让我可以根据 accountId 访问帐户文档。但我需要到达建筑物 > 网关 > 设备并找到匹配的设备。
更新:
我忘了提,我在这里处理 2 个系列。 感测结果和账目。
主要目的是从sensingresults中聚合数据,同时也从account collection中找到deviceId并返回结果。
这就是为什么需要查找来加入 2 个集合的原因?
更新2:
当前输出:
"accountId": ObjectId("5e1fe45cd05bfb0cc549297d"),
"avgZoneCountNumber": 0,
"avgZoneCountNumberInstant": 0,
"buildingId": ObjectId("5e1fe5e3d05bfb0cc5494146"),
"companyName": "The AAAAAA",
"createdAt": ISODate("1970-01-01T00:00:00Z"),
"dateHour": "2020-03-19T18",
"deviceId": ObjectId("5e1fe81ed05bfb0cc5496406"),
"gatewayId": ObjectId("5e1fe6a6d05bfb0cc5494d25"),
"minuteBucket": 1
预期结果:
"accountId": ObjectId("5e1fe45cd05bfb0cc549297d"),
"avgZoneCountNumber": 0,
"avgZoneCountNumberInstant": 0,
"buildingId": ObjectId("5e1fe5e3d05bfb0cc5494146"),
"createdAt": ISODate("1970-01-01T00:00:00Z"),
"dateHour": "2020-03-19T18",
"deviceId": ObjectId("5e1fe81ed05bfb0cc5496406"),
"gatewayId": ObjectId("5e1fe6a6d05bfb0cc5494d25"),
"minuteBucket": 1,
"serialNumber: 1, // this value should come from device object
"area": 1 // this value should come from device object
【问题讨论】:
请正确格式化代码块 我格式化并更新了问题 【参考方案1】:您可以使用$filter、$arrayElemAt 和$let 找到嵌套的device
:
device:
$let:
vars:
building:
$arrayElemAt: [ $filter: input: "$company_name.buildings", cond: $eq: [ "$$this._id", "$buildingId" ] , 0 ]
,
in:
$let:
vars:
gateway:
$arrayElemAt: [ $filter: input: "$$building.gateways", cond: $eq: [ "$$this._id", "$gatewayId" ] , 0 ]
,
in: $arrayElemAt: [ $filter: input: "$$gateway.devices", cond: $eq: [ "$$this._id", "$deviceId" ] , 0 ]
Full Solution
【讨论】:
我忘了说,我在这里处理 2 个系列。感测结果和账目。主要目的是聚合传感结果中的数据,也可以从账户集合中找到deviceId并返回结果。这就是为什么需要查找来加入 2 个集合的原因? mongoplayground.net/p/VV_9sBp57M4 我添加了我的原始聚合,请注意第一次查找只是从帐户中获取 companyName。我需要挖掘帐户并使用我拥有的那些 id 获取设备对象。 @newdeveloper 你也可以显示数据吗? Mongo Playground 可以处理多个集合,点击“docs”有一个例子 我创建了 2 个集合 - mongoplayground.net/p/iV7mdIL_-qv 它抛出了一个错误,但我认为它只是没有得到集合名称,你会知道我认为 @newdeveloper 谢谢,这有帮助,看看我修改后的答案以上是关于MongoDb:使用 $lookup 查找深度嵌套的对象的主要内容,如果未能解决你的问题,请参考以下文章