How can I count number of elements after query?

Viewed 7433

I have a query:

.modules[].resources | select (.[]!=null)

and after it I have got:

{ somestuff } { somestuff } { somestuff }

when I add legth after all:

.modules[].resources | select (.[]!=null) | length

I have got:

1 1 1

but I need to count elements, so I need 3 in an output. How can I implement it ?

In fact it would be very useful to create an array from the first query output to operate with it furthure

[ { somestuff } , { somestuff } , { somestuff } ]
3 Answers

You can put the results of the query into a list and get the length of this list:

[ .modules[].resources | select (.[]!=null) ] | length

Since you indicated it would be very useful to create an array from the first query output, what you probably want to use here is map.

Let's assume your data is something like the data from this question: jq: search by value from another array element

{
  "modules": [
    {
      "resources": [
        {
          "type": "openstack_compute_instance_v2",
          "primary": {
            "id": "5edfe2bf-94df-49d5-8118-3e91fb52946b",
            "attributes": {
              "name": "jumpbox"
            }
          }
        },
        {
          "type": "openstack_compute_floatingip_associate_v2",
          "primary": {
            "attributes": {
              "instance_id": "5edfe2bf-94df-49d5-8118-3e91fb52946b",
              "floating_ip": "10.120.241.21"
            }
          }
        }
      ]
    }
  ]
}

with this data your filter

   .modules[].resources 
 | select (.[]!=null)    #< do you really want this `[]` ?

would produce two copies of the entire .resources array. What you may want instead is

   .modules[].resources 
 | map(select(.!=null))

which will give you an array

[
  {
    "type": "openstack_compute_instance_v2",
    "primary": {
      "id": "5edfe2bf-94df-49d5-8118-3e91fb52946b",
      "attributes": {
        "name": "jumpbox"
      }
    }
  },
  {
    "type": "openstack_compute_floatingip_associate_v2",
    "primary": {
      "attributes": {
        "instance_id": "5edfe2bf-94df-49d5-8118-3e91fb52946b",
        "floating_ip": "10.120.241.21"
      }
    }
  }
]

to get the length, just add length:

  .modules[].resources
| map(select(.!=null))
| length

in this example giving

2

Because map(f) is defined as [ .[] | f ] the above filter is really

  .modules[].resources
| [
      .[]
    | select(.!=null)
  ]
| length

In this form you can clearly see the construction of the intermediate array.

Note also that jq provides a built-in values filter which is defined as select(.!=null) so this example could be further simplified to just

  .modules[].resources
| map(values)
| length

As mentioned at jq: count nest object values which satisfy condition

the best solution (e.g. because it does not involve construction of an intermediate array) would be to use count, defined as follows:

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

With this definition, you should be able simply to wrap count(...) around your query since it produces a stream:

count(.modules[].resources | select (.[]!=null))

Or maybe you want something closer to:

count(.modules[].resources | objects)
Related