How to check for presence of 'key' in jq before iterating over the values

JsonBashJq

Json Problem Overview


I get Cannot iterate over null (null) from the below query because .property_history is not present in result object.

How do i check for the presence of .property_history key before proceeding with map(...) ?

I tried using something like sold_year= `echo "$content" | jq 'if has("property_history") then map(select(.event_name == "Sold"))[0].date' else null end

Original Query:

sold_year=`echo "$content" | jq '.result.property_history | map(select(.event_name == "Sold"))[0].date'`

JSON:

{  
   "result":{  
      "property_history":[  
         {  
            "date":"01/27/2016",
            "price_changed":0,
            "price":899750,
            "event_name":"Listed",
            "sqft":0
         },
         {  
            "date":"12/15/2015",
            "price_changed":0,
            "price":899750,
            "event_name":"Listed",
            "sqft":2357
         },
         {  
            "date":"08/30/2004",
            "price_changed":0,
            "price":739000,
            "event_name":"Sold",
            "sqft":2357
         }
      ]
   }
}

Json Solutions


Solution 1 - Json

You can use the select-expression in jq to do what you intend to achieve, something as,

jq '.result 
  | select(.property_history != null) 
  | .property_history 
  | map(select(.event_name == "Sold"))[0].date'

Solution 2 - Json

Technically, to test for the presence of a property, you should use has/1, but in the present context, it would probably be better to use the postfix ? operator, e.g.:

$ jq '.result 
  | .property_history[]?
  | select(.event_name == "Sold") 
  | .date'
"08/30/2004"

Solution 3 - Json

use has("mykey1") (for objects) or has(0) (for arrays):

jq 'has("name")' <<< "{\"name\": \"hello\"}"

output:

true

Solution 4 - Json

The trick is to use // together with empty:

jq '.result.property_history // empty | map(select(.event_name == "Sold"))[0:1][].date'

Another alternative is to use an additional select:

jq '.result.property_history | select(.) | map(select(.event_name == "Sold"))[0:1][].date'

Solution 5 - Json

General pattern:

try (...) // "default_value"

With your logic:

jq 'try (.result.property_history | map(select(.event_name == "Sold"))[0].date) // "default_value"'

try (without a catch) returns empty if the expression fails. // provides a default value if the value is empty.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRahul DessView Question on Stackoverflow
Solution 1 - JsonInianView Answer on Stackoverflow
Solution 2 - JsonpeakView Answer on Stackoverflow
Solution 3 - Json123View Answer on Stackoverflow
Solution 4 - JsonreegnzView Answer on Stackoverflow
Solution 5 - JsonCurtis YallopView Answer on Stackoverflow