2

I have the following JSON. From there I'd like to count how many objects I have which type attribute is either "null" or has an array that contains the value "null". In the following example, the answer would be two. Note that the JSON could also be deeply nested.

{
  "A": {
    "type": "string"
  },
  "B": {
    "type": "null"
  },
  "C": {
    "type": [
      "null",
      "string"
    ]
  }
}

I came up with the following, but obviously this doesn't work since it misses the arrays. Any hints how to solve this?

jq '[..|select(.type?=="null")] | length'

0

2 Answers 2

2

This answer focuses on efficiency, straightforwardness, and generality.

In brief, the following jq program produces 2 for the given example.

  def count(s): reduce s as $x (0; .+1);

  def hasValue($value):
    has("type") and 
      (.type | . == $value or (type == "array" and any(. == $value)));

  count(.. | objects | select(hasValue("null")))

Notice that using this approach, it would be easy to count the number of objects having null or "null":

count(.. | objects | select(hasValue("null") or hasValue(null)))
Sign up to request clarification or add additional context in comments.

Comments

1

You were almost there. For arrays you could use IN. I also used objects, strings and arrays which are shortcuts to a select of the according types.

jq '[.. | objects.type | select(strings == "null", IN(arrays[]; "null"))] | length'
2

Demo


On larger structures you could also improve performance by not creating that array of which you would only calculate the length, but by instead just iterating over the matching items (e.g. using reduce) and counting on the go.

jq 'reduce (.. | objects.type | select(strings == "null", IN(arrays[]; "null"))) as $_ (0; .+1)'
2

Demo

2 Comments

@ikegami According to the repository, IN is defined as def IN(src; s): any(src == s; .);, thus purely any. (The lookup table is constructed by INDEX)
oh oops, yeah, mixed up IN and INDEX

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.