call-me-corgi
call-me-corgi

Reputation: 243

How to Iterate over an array of objets using jq

I have a javascript file which prints a JSON array of objects:

// myfile.js output
[
  { "id": 1, "name": "blah blah", ... },
  { "id": 2, "name": "xxx", ... },
  ...
]

In my bash script, I want to iterate through each object.

I've tried following, but it doesn't work.

#!/bin/bash

output=$(myfile.js)
for row in $(echo ${output} | jq -c '.[]'); do
  echo $row
done

Upvotes: 1

Views: 4487

Answers (2)

peak
peak

Reputation: 117027

How can I make jq -c '.[]' < (mongo myfile.js) work?

In a bash shell, you would write an expression along the following lines:

while read -r line ; do .... done < <(mongo myfile.js | jq -c .[])

Note that there are two occurrences of "<" in the above expression.

Also, the above assumes mongo is emitting valid JSON. If it emits //-style comments, those would have somehow to be removed.

Comparison with piping into while

If you use the idiom:

... | while read -r line ; do .... done

then the bindings of any variables in .... will be lost.

Upvotes: 1

costaparas
costaparas

Reputation: 5237

You are trying to invoke myfile.js as a command. You need this:

output=$(cat myfile.js)

instead of this:

output=$(myfile.js)

But even then, your current approach isn't going to work well if the data has whitespace in it (which it does, based on the sample you posted). I suggest the following alternative:

jq -c '.[]' < myfile.js |
while read -r row
do
  echo "$row"
done

Output:

{"id":1,"name":"blah blah"}
{"id":2,"name":"xxx"}

Edit: If your data is arising from a previous process invocation, such as mongo in your case, you can pipe it directly to jq (to remain portable), like this:

mongo myfile.js |
jq -c '.[]' |
while read -r row
do
  echo "$row"
done

Upvotes: 1

Related Questions