Mongodb 在递归结构中匹配关联类的字段

Mongodb 在递归结构中匹配关联类的字段,mongodb,mongodb-query,Mongodb,Mongodb Query,我将以下数据结构存储在MongoDB集合中 其中一个数据项如下所示: { "id": 0, ... "structure": { "id": 0, "name": "rsu2", "peers": [ { "networkQuality": { "name": "3G", "latency

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

其中一个数据项如下所示:

{
    "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中的一个递归查询来完成,按照您在问题中公开的方法,这是不雅观的。但我的选票还是很高