Joe
Joe

Reputation: 1011

How to insert a key-value pair after a specified key in a JSON object using jq?

I have a JSON file like this

{
    "hierarchy": {
        "structure": {
            "card_11001": [
                "addCard_4111"
            ],
            "container_11006": [
                "mainContainer_11007",
                "subContainer_10016"
            ],
            "mainContainer_11007": [
                "paymentMethodList_10001"
            ],
            "orderWrap_10012": [
                "orderSummary_10005"
            ],
            "paymentMethodList_10001": [
                "card_11001",
                "placeOrder_10013"
            ],
            "root_10000": [
                "payNotice_11011",
                "payNotice_10020",
                "container_11006",
                "placeOrderResultAction_10004"
            ],
            "subContainer_10016": [
                "orderWrap_10012",
                "footer_10014"
            ]
        }
    }
}

And I want to insert

"offline_11018": [
    "instruction_908",
    "checkboxList_11019"
]

Between "mainContainer_11007" and "orderWrap_10012" so the result I want should look like this:

{
    "hierarchy": {
        "structure": {
            "card_11001": [
                "addCard_4111"
            ],
            "container_11006": [
                "mainContainer_11007",
                "subContainer_10016"
            ],
            "mainContainer_11007": [
                "paymentMethodList_10001"
            ],
            "offline_11018": [
                "instruction_908",
                "checkboxList_11019"
            ],
            "orderWrap_10012": [
                "orderSummary_10005"
            ],
            "paymentMethodList_10001": [
                "card_11001",
                "placeOrder_10013"
            ],
            "root_10000": [
                "payNotice_11011",
                "payNotice_10020",
                "container_11006",
                "placeOrderResultAction_10004"
            ],
            "subContainer_10016": [
                "orderWrap_10012",
                "footer_10014"
            ]
        }
    }
}

All I know is that I can only append it to the end of file with

jq --raw-output '.hierarchy.structure + {"offline_11018": ["instruction_908","checkboxList_11019"]}'

But that's not what I want, I want to insert it between two other keys. How can I do it with the jq command?

Upvotes: 4

Views: 2226

Answers (1)

peak
peak

Reputation: 116967

The simplest approach would be to use to_entries to convert .hierarchy.structure into an array, perform the insertion, and then use from_entries to reconstitute the object, along the lines of:

.hierarchy.structure |= (to_entries
  | ... as $ix
  | .[:$ix] + ($x | to_entries) + .[$ix:]
  | from_entries)

The above sketch of course would need to be modified if it is possible that the item defining the insertion point cannot be found.

indexof/1

Here's a useful "def" for finding the least index for which some condition holds:

# If the input is an array, emit the least index, $i, 
# for which `.[$i]|f` is truthy, otherwise emit null.
# Works similarly if the input is a JSON object.
def indexof(f):
  label $out
  | foreach .[] as $x (null; .+1;
      if ($x|f) then (.-1, break $out) else empty end) // null;

Solution using indexof

Putting the above pieces together:

{"offline_11018": [ "instruction_908", "checkboxList_11019" ]} as $x
| .hierarchy.structure |= (to_entries
    | (1 + indexof( .value | index("mainContainer_11007") )) as $ix
    | .[:$ix] + ($x | to_entries) + .[$ix:]
    | from_entries)

Upvotes: 2

Related Questions