Search code examples
jsonjqdefault-value

Is there a way to use default in object construction with jq?


I want to filter and assign a value from array based on a condition, and use default in case if array does not have the matched object.

Here is a sample object:

{
    "array" : [
            {   
                "id": "A",
                "conversations": [   
                    {
                    "conversation": "1",
                    "type": "good"
                    },
                    {
                    "conversation": "2", 
                    "type": "bad"
                    }
                ]

            },
            {   
                "id": "B",
                "conversations": [   
                    {
                    "conversation": "3",
                    "type": "good"
                    },
                    {
                    "conversation": "4", 
                    "type": "bad"
                    }
                ]

            },
            {   
                "id": "C",
                "conversations": [   
                    {
                    "conversation": "5",
                    "type": "bad"
                    },
                    {
                    "conversation": "6", 
                    "type": "bad"
                    }
                ]

            }
        ]
}

Required output:

{
  "id": "A",
  "goodConversation": "1"
}
{
  "id": "B",
  "goodConversation": "3"
},
{
  "id": "C",
  "goodConversation": null
}

echo of my input:

echo '{"array":[{"id":"A","conversations":[{"conversation":"1","type":"good"},{"conversation":"2","type":"bad"}]},{"id":"B","conversations":[{"conversation":"3","type":"good"},{"conversation":"4","type":"bad"}]},{"id":"C","conversations":[{"conversation":"5","type":"bad"},{"conversation":"6","type":"bad"}]}]}'

I tried running following jq

jq '.array[] | {id, "goodConversation": .conversations[] | select(.type == "good") | .conversation}'

Actual output:

{
  "id": "A",
  "goodConversation": "1"
}
{
  "id": "B",
  "goodConversation": "3"
}

since the object with id: "C" does not have any good conversation the whole object gets filtered out. Is there a way to create the output object which contains "C" with null as value?

Clarification:

  • "conversations" will have at most one good conversation.
  • I am using jq 1.5

Solution

  • One way to provide a default value is often to use the // "alternative" operator. Building on the foundations you've laid, you could write:

    .array[]
    | {id, 
       "goodConversation": 
         ((.conversations[]
          | select(.type == "good")
          | .conversation) // null) }
    

    If there is more than one "good" conversation, however, this may not be exactly what you want. If it's not, then consider using first, e.g.:

    .array[]
    | {id,
       "goodConversation":
         ( first(.conversations[]
                 | select(.type == "good")
                 | .conversation) // null)}