基于键合并两个数组并使用 mongodb 聚合添加新字段

Posted

技术标签:

【中文标题】基于键合并两个数组并使用 mongodb 聚合添加新字段【英文标题】:Merge two arrays based on a key and add new filed using mongo aggregation 【发布时间】:2021-12-12 14:26:51 【问题描述】:

我需要编写一个聚合来使用条件将一个数组字段合并到另一个数组字段中。

示例: 原始文档:

[
        "key": 1,
        "risks": [
                "_id": "1234-risk1",
                "name": "risk1"
            , 
                "_id": "9999-risk2",
                "name": "risk2"
            
        ],
        "controls": [
                "identifier": "P8.1.3",
                "links": [
                        "entity": 
                            "valueKey": "1234-risk1"
                        
                    , 
                        "entity": 
                            "valueKey": "456"
                        
                    
                ]
            , 
                "identifier": "X8.1.3",
                "links": [
                        "entity": 
                            "valueKey": "1234-risk1"
                        
                    , 
                        "entity": 
                            "valueKey": "456"
                        
                    
                ]
            , 
            
                "identifier": "Y8.1.3",
                "links": [
                        "entity": 
                            "valueKey": "9999-risk2"
                        
                    , 
                        "entity": 
                            "valueKey": "456"
                        
                    
                ]
            ,
            
                "identifier": "A1.2.9",
                "links": [
                        "entity": 
                            "valueKey": "456"
                        
                    
                ]
            
        ]
    
]

字段 risk.id(例如:1234-risk1 和 9999-risk2)在控件数组字段中具有相关控件。 还有一些控件也不匹配任何 risk.id 匹配项。

我需要创建一个新的字段 riskControls 到俱乐部风险 + 其相应的控制(如果有),然后控制没有风险。

预期:

[
        "key": 1,
        "riskControls": [
                "_id": "1234-risk1",
                "name": "risk1",
                "controls": [
                        "identifier": "P8.1.3",
                        "links": [
                                "entity": 
                                    "valueKey": "1234-risk1"
                                
                            , 
                                "entity": 
                                    "valueKey": "456"
                                
                            
                        ]
                    , 
                        "identifier": "X8.1.3",
                        "links": [
                                "entity": 
                                    "valueKey": "1234-risk1"
                                
                            , 
                                "entity": 
                                    "valueKey": "456"
                                
                            
                        ]
                    
                ]
            , 
                "_id": "9999-risk2",
                "name": "risk2",
                "controls": [
                        "identifier": "Y8.1.3",
                        "links": [
                                "entity": 
                                    "valueKey": "9999-risk2"
                                
                            , 
                                "entity": 
                                    "valueKey": "456"
                                
                            
                        ]
                    
                ]
            , 
                //no risk details
                "controls": [
                        "identifier": "A1.2.9",
                        "links": [
                                "entity": 
                                    "valueKey": "456"
                                
                            
                        ]
                    
                ]
            
        ]
    
]

https://mongoplayground.net/p/MbRciOaKMHO

【问题讨论】:

【参考方案1】:

查询

找到控件 ID(值键) 查找 rnc-ids(没有控制 ID 的风险) 找到 cnr-id (>>) 用它来制作 3 个数组 rnc = 无法控制的风险 cnr = 没有风险的控制 rc = 可控的风险 连接所有 3 个 取消设置所有临时字段和风险控制

*查询很大,但是一个风险可能没有控制,一个控制可能没有风险,所以它就像控制的3个风险匹配

Test code here

aggregate(
["$set": 
    "controls-ids": 
      "$reduce": 
        "input": "$controls.links.entity.valueKey",
          "initialValue": [],
          "in": "$concatArrays": ["$$value", "$$this"],
  "$set": 
    "rnc-ids": "$setDifference": ["$risks._id", "$controls-ids"],
      "cnr-ids": "$setDifference": ["$controls-ids", "$risks._id"],
  "$unset": ["controls-ids"],
  "$set": 
    "cnr": 
      "$map": 
        "input": 
          "$filter": 
            "input": "$controls",
              "cond": 
              "$eq": 
                ["$setDifference": 
                    ["$$this.links.entity.valueKey", "$cnr-ids"],
                  []],
          "in": "controls": "$$c",
          "as": "c",
      "rnc": 
      "$map": 
        "input": 
          "$filter": 
            "input": "$risks", "cond": "$in": ["$$this._id", "$rnc-ids"],
          "in": "$mergeObjects": ["$$r", "controls": []],
          "as": "r",
      "rc": 
      "$map": 
        "input": 
          "$filter": 
            "input": "$risks",
              "cond": "$not": ["$in": ["$$this._id", "$rnc-ids"]],
          "in": 
          "$mergeObjects": 
            ["$$r",
              "controls": 
                "$filter": 
                  "input": "$controls",
                    "cond": "$in": ["$$r._id", "$$c.links.entity.valueKey"],
                    "as": "c"],
          "as": "r",
  "$set": "riskControls": "$concatArrays": ["$rc", "$rnc", "$cnr"],
  "$unset": 
    ["controls-ids", "rnc-ids", "cnr-ids", "cnr", "rnc", "rc", "risks",
      "controls"]])

【讨论】:

感谢@Takis 的帮助。它适用于大多数场景,除了一种。它不起作用的情况是 - 当我有没有任何控制的风险时,“riskControls”字段会填充该风险对象两次。示例 - mongoplayground.net/p/zG1EfSc2Spy 在此示例中,“7777-risk2”在 riskControls 中出现了两次 我更新了答案并且我认为现在可以工作,因为查询有点复杂和嵌套数组等,如果可以,请在使用前对其进行测试。 谢谢,成功了。

以上是关于基于键合并两个数组并使用 mongodb 聚合添加新字段的主要内容,如果未能解决你的问题,请参考以下文章

如何根据javascript中的键合并和替换两个数组中的对象?

mongodb聚合两个集合并添加新字段

MongoDB聚合在根中创建内部数组

Mongodb组和来自聚合方面的两个类似数据的数组相加

在mongodb聚合中将多个对象合并为一个对象

MongoDB聚合:将数组属性展平为根数组