0

Ok, i spent way to much time on this. Using jq, i want to test if an element exist in an array, if yes being able to mofify this element, if not adding this element to that array

I have read

Which gave hints But i am stuck

Let say i have a json file like :

    {
    "LOGIN":"user",
    "COPY": [
        {
            "CHAINLIST":"chain1",
            "ELEMENT": [ "element1-1","element1-2" ] 
        },
        {
            "CHAINLIST":"chain2",
            "ELEMENT": [ "element2-1","element2-2" ] 
        }
    ]
}

I Would like to add elements to the COPY array based in the CHAINLIST id , let say those 3 elements :

//ELEM A
{
       "CHAINLIST":"chain3",
       "ELEMENT": [ "element3-1" ] 
    }
//ELEM B
    {
       "CHAINLIST":"chain2",
       "ELEMENT": [ "element2-1","element2-3" ] 
    }
//ELEM C
    {
       "CHAINLIST":"chain1",
       "ELEMENT": [ "element1-1","element1-2" ] 
    }

ELEM A has the CHAINLIST id chain3 who doesn't exit in the COPY Array _> let's add it

ELEM B Is already present in the COPY aray, I want to update the ELEMENT array content with the new value

ELEM C Already exist and is up to date, i don't need to do anything.

In my example the final json object would be

    {
    "LOGIN":"user",
    "COPY": [
        {
            "CHAINLIST":"chain1",
            "ELEMENT": [ "element1-1","element1-2" ] 
        },
        {
            "CHAINLIST":"chain2",
            "ELEMENT": [ "element2-1","element2-2","element2-3" ] 
        },
        {
            "CHAINLIST":"chain3",
            "ELEMENT": [ "element3-1"] 
        }
     ]
    }

I am using jq The procedure to add the element Elem to the object Obj would be :

Elem.CHAINLIST exist in Obj.COPY [] ?

yes : add Elem.ELEMENT to Obj.ELEMENT[] with unique to qvoid duplicates

no : add Elem to Obj.COPY[]

The best i get is

    (if .COPY[]? | select (.CHAINLIST=="chain3") == "" then . else .COPY[.COPY | length ] |= . + { "CHAINLIST":"chain3","ELEMENT":[ "element3-1"]}  end ) 

But select (.CHAINLIST=="chain3") == "" return nothing I i can figure out how to test if empty.

Thank you for your time !

Aplantie
  • 15
  • 5

1 Answers1

0

The following solution uses the built-in function INDEX/2 to create convenient and efficient representations of the collections of CHAINLIST-ELEMENT objects, together with a bespoke function, augment/1, for combining elements.

It is assumed that the objects defining the updates are presented as an array in the file edits.json.

< input.json jq --argfile edits edits.json '

  # Use `unique` to combine the .ELEMENT fields
  def augment($b):
     reduce ($b|keys_unsorted[]) as $key (.; 
       .[$key].ELEMENT = (.[$key].ELEMENT + $b[$key].ELEMENT | unique));

  (INDEX($edits[];.CHAINLIST) | map_values(del(.CHAINLIST))) as $edits
  | (INDEX(.COPY[]; .CHAINLIST) | map_values(del(.CHAINLIST))) as $COPY
  | .COPY |= ($COPY
              | augment($edits)
              | to_entries
              | map( { CHAINLIST: .key, ELEMENT: .value.ELEMENT} ))

Output: as specified in the question.

Note: if the objects defining the updates are presented as a sequence of objects in a file, you could use the above solution with --slurpfile instead of --argfile.

peak
  • 105,803
  • 17
  • 152
  • 177