skip to Main Content

I want to transform this JSON

{
    "property": "value",
    "array1": [
        {
            "name": "A",
            "propertyA1": "1",
            "propertyA2": "2"
        },
        {
            "name": "B",
            "propertyB1": "1",
            "array2": [
                {
                    "name": "C",
                    "propertyC1": "1",
                    "propertyC2": "2"
                }
            ]
        }
    ]
}

into that using a JQ filter.

{
    "property": "value",
    "array1": {
        "A": {
            "propertyA1": "1",
            "propertyA2": "2"
        },
        "B" : {
            "propertyB1": "1",
            "array2": {
                "C" : {
                    "propertyC1": "1",
                    "propertyC2": "2"
                }
            }
        }
    }
}

The difficulty is to make this work recursively. Moreover, only arrays who
possess an object with a property name should be considered. I had a few attempts but
it already fails if I want to add a new property do the arrays (I know it’s not possible,
since it is an array).

2

Answers


  1. You can use a recursive function that iterates through each element of the array and checks if it possesses an object with a property name. If it does, then the function calls itself again with the updated array. This way, the function will iterate through all elements of the array and check if they possess an object with a property name.

    function checkArray(arr) {
      let current = arr;
      while (current.length > 0)) {
        const obj = current[current.length - 1]];
        if (obj && 'object' === typeof obj)) {
          current.pop(current.length - 1]);
          continue;
        }
      }
      return current;
    }
    
    // Test the function
    const array1 = [
      { "name": "A", "propertyA1": "1", "propertyA2": "2" }  
    ];
    const array2 = [
      { "name": "C", "propertyC1": "1", "propertyC2": "2" }  
    ];
    console.log(checkArray(array1))))
    
    Login or Signup to reply.
  2. You basically want to turn each array into an object with each item’s .name field turned into a key. You could use from_entries which requires each key and value as .name (or .key) and .value fields, so all you have to do is to set up a .value without the .name field. walk the document tree to apply this to each array.

    walk(arrays |= (map(.value = del(.name)) | from_entries))
    
    {
      "property": "value",
      "array1": {
        "A": {
          "propertyA1": "1",
          "propertyA2": "2"
        },
        "B": {
          "propertyB1": "1",
          "array2": {
            "C": {
              "propertyC1": "1",
              "propertyC2": "2"
            }
          }
        }
      }
    }
    

    Demo

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search