Mongodb 在递归结构中匹配关联类的字段
我将以下数据结构存储在MongoDB集合中 其中一个数据项如下所示:Mongodb 在递归结构中匹配关联类的字段,mongodb,mongodb-query,Mongodb,Mongodb Query,我将以下数据结构存储在MongoDB集合中 其中一个数据项如下所示: { "id": 0, ... "structure": { "id": 0, "name": "rsu2", "peers": [ { "networkQuality": { "name": "3G", "latency
{
"id": 0,
...
"structure": {
"id": 0,
"name": "rsu2",
"peers": [
{
"networkQuality": {
"name": "3G",
"latency": "200ms",
"bandwidth": "1000kbps"
},
"connectionEndpoint": {
"id": 1,
"name": "vehicle1",
"peers": []
}
},
{
"networkQuality": {
"name": "3G",
"latency": "200ms",
"bandwidth": "1000kbps"
},
"connectionEndpoint": {
"id": 2,
"name": "vehicle2",
"peers": []
}
}
]
}
}
我的问题是:如何检索任何两个节点之间的所有连接都具有networkQuality.name='3G'的拓扑。这是我的想法,但由于我在MongoDB方面还不是很有经验,所以我不知道如何将它精确地表述为一个工作查询
- 由于它是一个递归结构,我将使用$where操作符()中定义的javascript函数来匹配递归结构中的networkQuality.name='3G'
- 通过上一点中描述的方法,我将检索至少具有一个networkQuality.name='3G'的所有拓扑以及至少具有一个networkQuality.name='3G'的拓扑3G’。这样做后,我有两套。当我对这些(第一个结果-第二个结果)应用set减号操作时,我将获得所需的结果
有人知道怎么做吗?不幸的是,我不能只用一个查询来解决这个问题,但我找到了两个查询,并在它们之间进行了简单的“Javascript处理” 第一个变化是,我不在同一个集合中存储具有嵌入节点的拓扑,但我有一个集合用于我的拓扑,另一个集合用于节点。
拓扑集合结构很简单:
{
"caption": "small-i=1-net=3G"
"id": 0
"specification": "tosca"
"specificationLang": "tosca"
"structure_root_node_id": 0
}
我决定将节点结构存储为带有子引用的树。正如mongodb docu建议的那样
表示表示节点的文档存储方式如下:
{
"id": 0
"connections" : [
{
"networkQuality" :
{
"name" : "3G",
"latency" : "200ms",
"bandwidth" : "1000kbps"
},
"endpoint_id" : 1
},
{
"networkQuality" :
{
"name" : "3G",
"latency" : "200ms",
"bandwidth" : "1000kbps"
},
"endpoint_id" : 2 }
],
"name" : "edge1",
"nodeType" : 1
}
这是我的解决方案:1。检索属于同一拓扑的所有节点ID:
我将拓扑与根节点连接起来,然后使用图查找来获取属于同一拓扑的所有节点
[{$lookup: {
from: 'node_structure',
localField: 'structure_root_node_id',
foreignField: 'id',
as: 'structure'
}}, {$graphLookup: {
from: 'node_structure',
startWith: '$structure.id',
connectFromField: 'connections.endpoint_id',
connectToField: 'id',
as: 'endpoints'
}}, {$project: {
"endpoints.id": 1
}}]
{
"_id" : ObjectId("5c5af8c6dfe2bc05bfc6ed0b"),
"endpoints" :
[
{ "id" : 4 },
{ "id" : 1 },
{ "id" : 0 },
{ "id" : 2 },
{ "id" : 3 }
]
}
通过运行上述管道,我获得了一个包含拓扑的所有节点ID的数组
[{$lookup: {
from: 'node_structure',
localField: 'structure_root_node_id',
foreignField: 'id',
as: 'structure'
}}, {$graphLookup: {
from: 'node_structure',
startWith: '$structure.id',
connectFromField: 'connections.endpoint_id',
connectToField: 'id',
as: 'endpoints'
}}, {$project: {
"endpoints.id": 1
}}]
{
"_id" : ObjectId("5c5af8c6dfe2bc05bfc6ed0b"),
"endpoints" :
[
{ "id" : 4 },
{ "id" : 1 },
{ "id" : 0 },
{ "id" : 2 },
{ "id" : 3 }
]
}
2。这是JS处理步骤,我必须将ID从端点数组提取到以下形式:[4,1,0,2,3](如果我可以作为管道的一部分来做这件事,那就太好了,但不知道是否可能)
3。执行查找
{
$and: [
{ connections: { $elemMatch: { 'networkQuality.name': { $nin: ['3G'] } } } },
{ id: { $in: [0, 1, 2, 3, 4] } }
]
}
这将返回至少有一个连接不同于“3G”的任何节点,这意味着如果查询未返回任何内容,我将找到任何两个节点之间具有网络质量的所有连接的拓扑。名称=“3G”。只需一个查询就可以解决所有问题,但这是我目前找到的唯一解决方案。(注意:我不想在一个拓扑字段中存储所有拓扑的节点ID)如果有一个答案不使用递归部分的自定义js函数,我会很高兴。至于您的问题:只需使用聚合管道,使用{$match:{$where:…}}两次,一次用于=='3G',另一次用于!='3G'@NunoSousa检查我下面的答案。将嵌入式结构更改为关系结构,虽然对于实际情况来说是有意义的,但有点违背了问题的目的。顺便说一句,您可以用javascript中的一个递归查询来完成,按照您在问题中公开的方法,这是不雅观的。但我的选票还是很高