1
[ 
{ "id":"1", 
  "metadata":{"version":"1.0","author":"user1"}
},
{ "id":"2", 
  "metadata":{"version":"1.0","author":"user2","timestamp":"2019-02-05"}
},
{ "id":"3", 
  "metadata":{"version":"1.0","author":"user3","price":"10.0"}
}]

I am trying to parse the above json (data1.json) using jq, but I am unable to access the metadata object. I will eventually use the metadata object to insert into a database as a string. It can have any number of fields, the structure is not fixed. This is the script that I'm using.

#!/usr/bin/env bash
id=($(jq '.[] | .id' data1.json | tr -d '"'))
metadata=($(jq '.[] | .metadata' data1.json))

n_id=${#id[@]}
n_meta=${#metadata[@]}

echo $n_id 
echo $n_meta 

for (( i=0; i<n_id; i++ )); do
    echo ${metadata[$i]} 
done

Expected output:

{"version":"1.0","author":"user1"}

{"version":"1.0","author":"user2","timestamp":"2019-02-05"}

{"version":"1.0","author":"user3","price":"10.0"}

What am I doing wrong here? Any help is appreciated.

3 Answers 3

2

All the metadata objects, one per line, not wrapped in an array?

$ jq -c '.[] | .metadata' data1.json
{"version":"1.0","author":"user1"}
{"version":"1.0","author":"user2","timestamp":"2019-02-05"}
{"version":"1.0","author":"user3","price":"10.0"}

But you're already doing just that for your metadata array in your shell code. If you want to print that array one per line:

printf "%s\n" "${metadata[@]}"

To get the lines printed by jq into an array when there are spaces in the object contents:

mapfile -t metadata < <(jq -c '.[] | .metadata' data1.json)

or

while IFS= read -r obj; do metadata+=("$obj"); done < <(jq -c '.[] | .metadata' data1.json)
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much! This works!! but I see one small problem, if there is space in one of the values, the object is not stored as expected. For example, if "author":"fname lname" has spaces in all the metadata objects, it breaks off after fname.
@prathyusha Added a few ways to populate the array that avoid that problem.
1

You can do this using jtc:

If the above content is in the file foo.json, you can do:

% <foo.json jtc -tc -w '<metadata>l:'
{ "author": "user1", "version": "1.0" }
{ "author": "user2", "timestamp": "2019-02-05", "version": "1.0" }
{ "author": "user3", "price": "10.0", "version": "1.0" }

-tc means "compact output format"

-w .. is the walk path

<metadata> match on 'metadata', l means label match, : means 'all'

1 Comment

it's better to use -r option to ensure single row output for walks. thus the complete answer would be: while IFS= read -r obj; do metadata+=("$obj"); done < <(jtc -w'<metadata>l:' -r data1.json)
0

Why not just filter your data with jq itself?

jq -c '.[] | .metadata' data1.json

Please refer to Shawn's answer as I have not accounted for other data.

1 Comment

I do not know the contents of metadata, it can be anything.. so I can't set the fields like you mentioned.

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.