Home > other >  How to move nested objects to a different object in jq?
How to move nested objects to a different object in jq?

Time:12-13

I need to restructure some JSON files to clean up the data representation. Part of this restructuring includes grouping similar objects in a parent object rather than relying on a particular property of the object. We will have five "sections" in the files:

attributes, associatedObjects, inheritedObjects, enumerations, which will be used to represent "active" objects, and then a deprecated section that has those same four subgroups to denote, well, "deprecated" objects. The deprecated objects will be subject to later removal.

Given a structure such as:

    "attributes": {
        "alpha": {
            "deprecated": true,
            "description": "A description of alpha.",
            "dataType": "string"
        },
        "beta": {
            "deprecated": false,
            "description": "A description of beta.",
            "dataType": "associated object",
            "associatedObject": "gamma"
        },
        "kappa": {
            "deprecated": false,
            "description": "A description of kappa.",
            "dataType": "string"
        }
    }
}

How might I reorganize the file using jq to appear more like the following?

    "deprecations": {
        "attributes": {
            "alpha": {
                "description": "A description of alpha.",
                "dataType": "string"
            }
        },
        "enumerations": {},
        "associatedObjects": {},
        "inheritedObjects": {}
    },
    "attributes": {
        "kappa": {
            "description": "A description of kappa.",
            "dataType": "string"
        }
    },
    "enumerations": {},
    "associatedObjects": {
        "beta": {
            "description": "A description of beta.",
            "dataType": "gamma"
        }
    },
    "inheritedObjects": {}
}

I've only been able to add the new, empty sections (without any nesting) at the same level as attributes via jq '.associatedObjects = {} | .inheritedObjects = {} | .enumerations = {} | .deprecations = {} '

I attempted to move the item flagged as deprecated via this command:

jq '.attributes | keys[] as $k | 
if (.[$k].deprecated == true) then 
(del(.[$k].deprecated) | .deprecated  = .[$k] | del(.[$k])) 
else empty end '

but this results in invalid JSON and seems to duplicate the structure. I've also not been able to combine it with the creation of the new sections. It appears I don't have to create those new sections separately and/or beforehand.

What would it take to achieve this goal?

CodePudding user response:

I cannot entirely follow the criteria for your distribution, especially .enumerations and .inheritedObjects are unclear, but this could get you going:

.attributes | (map_values(select(.dataType == "string")) | {
  deprecations: map_values(select(.deprecated)),
  attributes: map_values(select(.deprecated | not))
})   {
  associatedObjects: map_values(select(.dataType == "associated object"))
}
{
  "deprecations": {
    "alpha": {
      "deprecated": true,
      "description": "A description of alpha.",
      "dataType": "string"
    }
  },
  "attributes": {
    "kappa": {
      "deprecated": false,
      "description": "A description of kappa.",
      "dataType": "string"
    }
  },
  "associatedObjects": {
    "beta": {
      "deprecated": false,
      "description": "A description of beta.",
      "dataType": "associated object",
      "associatedObject": "gamma"
    }
  }
}

Demo

CodePudding user response:

This should generate the expected output :

jq '(.attributes | map_values(select(.deprecated))) as $dep
    | .depreciations.attributes = ($dep | map_values(del(.deprecated)))
    | (.attributes | map_values(select(has("associatedObject")))) as $assoc
    | .associatedObjects = ($assoc
                           | map_values(.dataType = .associatedObject)
                           | map_values(del(.deprecated, .associatedObject))
                           )
    | .attributes |= del(.[]|select(.deprecated))
    | .attributes |= del(.[]|select(has("associatedObject")))
    | .attributes[] |= del(.deprecated)
    | .depreciations  = { "enumerations": {}, "associatedObjects": {}, "inheritedObjects": {} }
    | .   { "enumerations": {}, "inheritedObjects": {} }
' input.json
{
  "attributes": {
    "kappa": {
      "description": "A description of kappa.",
      "dataType": "string"
    }
  },
  "depreciations": {
    "attributes": {
      "alpha": {
        "description": "A description of alpha.",
        "dataType": "string"
      }
    },
    "enumerations": {},
    "associatedObjects": {},
    "inheritedObjects": {}
  },
  "associatedObjects": {
    "beta": {
      "description": "A description of beta.",
      "dataType": "gamma"
    }
  },
  "enumerations": {},
  "inheritedObjects": {}
}
  • Related