以递归结构匹配关联类的字段

时间:2019-02-04 17:35:30

标签: mongodb mongodb-query

我将以下数据的数据结构存储在MongoDB集合中。

data model

其中一个数据条目如下所示:

{
    "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运算符(as done here)中定义的javascript函数在递归结构中的任何位置匹配networkQuality.name ='3G'。
  • 通过上一点所述的方法,我将检索具有至少一个networkQuality.name ='3G'的所有拓扑和具有至少一个networkQuality.name!='3G'的拓扑。完成此操作后,我有两套。当我对它们(第一个结果-第二个结果)应用集合减运算时,我将获得所需的结果。

有人知道怎么做吗?

1 个答案:

答案 0 :(得分:1)

不幸的是,我无法仅使用单个查询来解决此问题,但是我发现了两个查询,并在它们之间进行了简单的“ JavaScript处理”。

第一个更改是,我没有在同一集合中存储带有嵌入式节点的拓扑,但是我有一个集合用于我的拓扑,另一个集合用于节点。
拓扑收集结构很简单:

{
    "caption": "small-i=1-net=3G"
    "id": 0
    "specification": "tosca"
    "specificationLang": "tosca"
    "structure_root_node_id": 0
}

我决定将Node结构存储为带有子引用的树。正是mongodb docu建议使用here

表示代表节点的文档的存储方式如下:

{ 
    "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的数组。

{ 
    "_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”的连接的节点,这意味着如果查询未返回任何内容,则我发现拓扑具有两个具有网络质量的任何节点之间的所有连接。name='3G'。
只需一个查询即可解决所有问题,但这是我目前发现的唯一解决方案。 (注意:我不想在拓扑字段中存储所有拓扑的节点ID)