jsonjq

Jq create object fails when key is missing


I have two example files

example1:

{
  "label": "Example1",
  "attributes": [
    {
       "objectTypeAttribute": {
        "name": "Created"},
      "objectAttributeValues": [
        {
          "value": "create time 1"
        }
      ]
    },
    {
      "objectTypeAttribute": {
        "name": "Updated"},
      "objectAttributeValues": [
        {
          "value": "update time 1"
        }
      ]
    }
  ]
}

and example2

{
  "label": "Example2",
  "attributes": [
    {
       "objectTypeAttribute": {
        "name": "Created"},
      "objectAttributeValues": [
        {
          "value": "create time 2"
        }
      ]
    }
  ]
}

When I apply

cat example1 | jq '{created: .attributes[] | select(.objectTypeAttribute.name=="Created").objectAttributeValues[0].value,
updated:.attributes[] | select(.objectTypeAttribute.name=="Updated").objectAttributeValues[0].value}'

on the first everything works fine and I get expected result

{
  "created": "create time 1",
  "updated": "update time 1"
}

, however applying

cat example2 | jq '{created: .attributes[] | select(.objectTypeAttribute.name=="Created").objectAttributeValues[0].value,
updated:.attributes[] | select(.objectTypeAttribute.name=="Updated").objectAttributeValues[0].value}'

I get no result at all, the result i would expect is

{
  "created": "create time 2",
  "created": "NULL"
}

After researching similar questions I have tried the following:

cat example2 | jq 'try (.attributes[] | select(.objectTypeAttribute.name=="Created").objectAttributeValues[0].value) // "NULL", try (.attributes[] | select(
.objectTypeAttribute.name=="Updated").objectAttributeValues[0].value) // "NULL"'

however this doesn't work when I try rewriting the key like here:

cat example2 | jq '{created: (try (.attributes[] | select(.objectTypeAttribute.name=="Created").objectAttributeValues[0].value) // "NULL"), updated: try (.a
ttributes[] | select(.objectTypeAttribute.name=="Updated").objectAttributeValues[0].value) // "NULL"}'

Also I have tried

cat example2 | jq '{created: (.attributes[] | select(.objectTypeAttribute.name=="Created").objectAttributeValues[0].value? //"null1"),
updated: (.attributes[] | select(.objectTypeAttribute.name=="Updated").objectAttributeValues[0].value? //"NULL")}'

which works for example2 but doesn't for example1

cat example1 | jq '{created: (.attributes[] | select(.objectTypeAttribute.name=="Created").objectAttributeValues[0].value? //"NULL"),
updated: (.attributes[] | select(.objectTypeAttribute.name=="Updated").objectAttributeValues[0].value? //"NULL")}'

which results in

{
  "created": "create time 1",
  "updated": "NULL"
}
{
  "created": "create time 1",
  "updated": "update time 1"
}
{
  "created": "NULL",
  "updated": "NULL"
}
{
  "created": "NULL",
  "updated": "update time 1"
}
enter code here

Solution

  • It seems you'll need additional parenthesis, as otherwise // binds stronger than the | and you're piping all attributes through an expression that always returns a value.

    {
        created: ((.attributes[] | select(.objectTypeAttribute.name=="Created").objectAttributeValues[0].value) // null),
        updated: ((.attributes[] | select(.objectTypeAttribute.name=="Updated").objectAttributeValues[0].value) // null),
    }
    

    (online demo)


    An imo simpler solution is to build the objects dynamically with the specified key names and values, using from_entries:

    .attributes | map({
        key: .objectTypeAttribute.name | ascii_downcase,
        value: .objectAttributeValues[0].value
    }) | from_entries
    

    (online demo)

    … or add:

    .attributes | map({
        (.objectTypeAttribute.name | ascii_downcase): .objectAttributeValues[0].value
    }) | add
    

    (online demo)