Home > Enterprise >  Merge two arrays based on common key, keeping unmatched values
Merge two arrays based on common key, keeping unmatched values

Time:09-14

Given this data I am trying to return the servers array with any matches from groups array based on s_Group value. However group_by(s_Group) only returns those common to both arrays (with one extraneous non-match I cannot explain). It might be worth mentioning this is being done in a bash script so I am game to break the arrays into separate files and/or multiple steps if that makes things easier.

EDIT: I should have specified I want all the attributes from groups pulled into the new servers elements where a match occurs. Apologies for not making that clear. Adding a "desired output".

input data:

{
    "servers": [
        {
            "location": "srv_apc1",
            "f_Group": "auc-1"
        },
        {
            "location": "srv_apc2",
            "f_Group": "auc-1",
            "c_Group": "c1"
        },
        {
            "location": "srv_apc3",
            "f_Group": "auc-1",
            "c_Group": "c2"
        },
        {
            "location": "srv_apc4",
            "f_Group": "auc-1",
            "c_Group": "c3"
        },
        {
            "location": "srv_wc1",
            "s_Group": "cb-1"
        },
        {
            "location": "srv_wc2",
            "s_Group": "cb-2"
        },
        {
            "location": "srv_wc3",
            "s_Group": "cb-3"
        },
        {
            "location": "srv_wc4",
            "s_Group": "cb-4"
        }
    ],
    "groups": [
        {
            "s_Group": "cb-1",
            "options": [
                "opt1",
                "opt3",
                "opt5",
                "home"
            ]
        },
        {
            "s_Group": "cb-2",
            "options": [
                "opt2",
                "opt4",
                "opt6",
                "home"
            ]
        },
        {
            "s_Group": "cb-3",
            "options": [
                "opt7",
                "opt8",
                "opt9",
                "home",
                "print"
            ]
        },
        {
            "s_Group": "cb-4",
            "options": [
                "ems99",
                "erec98",
                "expr-77",
                "home"
        ]
        },
        {
            "s_Group": "extra-99",
            "options": [
                "conf1",
                "ems34",
                "erec1",
                "home",
                "chec99",
                "franT"
            ]
        }
    ]
}

jq:

.servers   .groups | group_by(.s_Group) | map(add)

Demo

desired output:

{
    "servers": [
        [
            {
                "location": "srv_apc1",
                "f_Group": "auc-1"
            },
            {
                "location": "srv_apc2",
                "f_Group": "auc-1",
                "c_Group": "c1"
            },
            {
                "location": "srv_apc3",
                "f_Group": "auc-1",
                "c_Group": "c2"
            },
            {
                "location": "srv_apc4",
                "f_Group": "auc-1",
                "c_Group": "c3"
            },
            {
                "location": "srv_wc1",
                "s_Group": "cb-1",
                "options": [
                    "opt1",
                    "opt3",
                    "opt5",
                    "home"
                ]
            },
            {
                "location": "srv_wc2",
                "s_Group": "cb-2",
                "options": [
                    "opt2",
                    "opt4",
                    "opt6",
                    "home"
                ]
            },
            {
                "location": "srv_wc3",
                "s_Group": "cb-3",
                "options": [
                    "opt7",
                    "opt8",
                    "opt9",
                    "home",
                    "print"
                ]
            },
            {
                "location": "srv_wc4",
                "s_Group": "cb-4",
                "options": [
                    "ems99",
                    "erec98",
                    "expr-77",
                    "home"
                ]
            }
        ]
    ]
}

CodePudding user response:

Everything can be done with one invocation of jq. If I understand the requirements correctly, you could use the following jq program:

  INDEX(.groups[]; .s_Group) as $dict
  | .servers 
  | map( .   $dict[.f_Group // ""])

This returns the modified .servers array.

CodePudding user response:

Use JOIN with an INDEX on the .servers items:

jq '{servers: [JOIN(
  INDEX(.groups[]; .s_Group); .servers[]; .s_Group // empty; add
)]}'
{
  "servers": [
    {
      "location": "srv_apc1",
      "f_Group": "auc-1"
    },
    {
      "location": "srv_apc2",
      "f_Group": "auc-1",
      "c_Group": "c1"
    },
    {
      "location": "srv_apc3",
      "f_Group": "auc-1",
      "c_Group": "c2"
    },
    {
      "location": "srv_apc4",
      "f_Group": "auc-1",
      "c_Group": "c3"
    },
    {
      "location": "srv_wc1",
      "s_Group": "cb-1",
      "options": [
        "opt1",
        "opt3",
        "opt5",
        "home"
      ]
    },
    {
      "location": "srv_wc2",
      "s_Group": "cb-2",
      "options": [
        "opt2",
        "opt4",
        "opt6",
        "home"
      ]
    },
    {
      "location": "srv_wc3",
      "s_Group": "cb-3",
      "options": [
        "opt7",
        "opt8",
        "opt9",
        "home",
        "print"
      ]
    },
    {
      "location": "srv_wc4",
      "s_Group": "cb-4",
      "options": [
        "emsar",
        "ereceipt",
        "expressmtreceive",
        "home",
        "mtagentlookup",
        "mtreceive",
        "mtstatus"
      ]
    }
  ]
}

Demo

  • Related