Assigning parent keys in innermost object using JQ - json

I would like to turn this:
{
"a": 1,
"b": [1,2,3,4]
}
into this
[
{"a": 1, "b": 1},
{"a": 1, "b": 2},
...
]
This is sort of like python's zip but with unequally shaped objects.
Thanks!

Here is a solution:
$ jq -Mc '[.b=.b[]]' data.json
If data.json contains the sample data the output is
[{"a":1,"b":1},{"a":1,"b":2},{"a":1,"b":3},{"a":1,"b":4}]

You can use cat ab.json|jq '[{"a": .a, "b": .b[]}]' to get the answer.

If minimizing keystrokes is the goal, then consider:
jq '.+{b:.b[]}' <<< "$j"
{
"a": 1,
"b": 1
}
{
"a": 1,
"b": 2
}
{
"a": 1,
"b": 3
}
{
"a": 1,
"b": 4
}
Using . here ensures that all keys other than "b" will be preserved. By contrast, if one wants to ignore all the keys other than "a" and "b", then one could use the jq filter:
{a,b:.b[]}
To turn the stream into an array, just wrap the expression in square brackets: [ ... ]

Related

Sorting a list of data's in json format

So I am trying to sort through a good few lines of text and numbers in JSON format. An example of some of these lines would be
{ "a": "123456", "b": 16, "c": "Data" }
{ "a": "654321", "b": 30, "c": "Data" }
{ "a": "015864", "b": 18, "c": "Data" }
I am trying to sort these in a way that the value for B (16, 30, and 18, respectively) is sorted from largest to lowest. Example:
{ "a": "654321", "b": 30, "c": "Data" }
{ "a": "015864", "b": 18, "c": "Data" }
{ "a": "123456", "b": 16, "c": "Data" }
I know it is possible, but I have 0 idea how regex works, or if there is something else I could use. Preferably able to be done from a linux command line, but if it needs to be done with notepad++ or something I can make it work. Also please explain why your suggestion works so I can learn, not just copy-paste your suggestion. Thank you!!
Edit: I was informed Regex would not work. I am okay with any scripting language being used, as long as I can learn how to do these things myself. Python, Perl, php, any of them work.
if the fields are aligned you can sort as if it's a text file.
$ sort -k5,5nr file
{ "a": "654321", "b": 30, "c": "Data" }
{ "a": "015864", "b": 18, "c": "Data" }
{ "a": "123456", "b": 16, "c": "Data" }
field are space delimited, sorting based on field 5 values (which are b values), numerical reverse sort.

Linux command to print all jsons of same key

I have json as a string "Str"
"{
"A": {
"id": 4
},
"B": {//Something},
"C": {
"A": {
"id": 2
}
},
"E": {
"A": null
},
"F": {//Something}
}"
I wanted all non null values of "A" which can be repeated anywhere in json. I wanted output like all contents of "A"
{"id": 4}
{"id": 2}
Can you please help me with Linux command to get this ?
Instead of line oriented ones use a tool which is capable of parsing JSON values syntax wise. An example using jq:
$ json_value='{"A":{"id":4},"B":{"foo":0},"C":{"A":{"id":2}},"E":{"A":null},"F":{"foo":0}}'
$
$ jq -c '..|objects|.A//empty' <<< "$json_value"
{"id":4}
{"id":2}
.. # list nodes recursively
| objects # select objects
| .A // empty # print A's value if present.

JQ: how can I remove keys based on regex?

I would like to remove all keys that start with "hide". Important to note that the keys may be nested at many levels. I'd like to see the answer using a regex, although I recognise that in my example a simple contains would suffice. (I don't know how to do this with contains, either, BTW.)
Input JSON 1:
{
"a": 1,
"b": 2,
"hideA": 3,
"c": {
"d": 4,
"hide4": 5
}
}
Desired output JSON:
{
"a": 1,
"b": 2,
"c": {
"d": 4
}
}
Input JSON 2:
{
"a": 1,
"b": 2,
"hideA": 3,
"c": {
"d": 4,
"hide4": 5
},
"e": null,
"f": "hiya",
"g": false,
"h": [{
"i": 343.232,
"hide9": "private",
"so_smart": true
}]
}
Thanks!
Since you're just checking the start of the keys, you could use startswith/1 instead in this case, otherwise you could use test/1 or test/2. Then you could pass those paths to be removed to delpaths/1.
You might want to filter the key by strings (or convert to strings) beforehand to account for arrays in your tree.
delpaths([paths | select(.[-1] | strings | startswith("hide"))])
delpaths([paths | select(.[-1] | strings | test("^hide"; "i"))])
A straightforward approach to the problem is to use walk in conjunction with with_entries, e.g.
walk(if type == "object"
then with_entries(select(.key | test("^hide") | not))
else . end)
If your jq does not have walk/1 simply include its def (available e.g. from https://raw.githubusercontent.com/stedolan/jq/master/src/builtin.jq) before invoking it.

How to escape quotes in a JSON value with JQ when JSON is not valid yet

I have invalid JSON like this:
{
"a": "value1",
"b": "value2",
"c": "value3"
}
{
"a": "value4",
"b": "value5",
"c": "value6"
}
{
"a": "value7",
"b": "value8",
"c": "value9"
}
I can easily make it valid with JQ -- jq . -s -- which outputs:
[
{
"a": "value1",
"b": "value2",
"c": "value3"
},
{
"a": "value4",
"b": "value5",
"c": "value6"
},
{
"a": "value7",
"b": "value8",
"c": "value9"
}
]
But when my invalid JSON contains quotes...
{
"a": "value1",
"b": "value with "quotes"2",
"c": "value with "more" than one set of "quotes"3"
}
{
"a": "value4",
"b": "value with "quotes"5",
"c": "value with "more" than one set of "quotes"6"
}
{
"a": "value7",
"b": "value with "quotes"8",
"c": "value with "more" than one set of "quotes"9"
}
...that JQ command obviously won't work because of the quotes within quotes.
My goal is to make my original JSON completely valid both in (1) structure and (2) with quotes in values escaped. I don't want any other quotes escaped than those inside the value -- for example:
"c": "value with \"more\" than one set of \"quotes\"9",
I have written a number of one-off Bash sed scripts to search and replace unescaped quotes with escaped quotes, but as use cases grow so do the number of scripts. It seems like JQ may be powerful and elegant enough to handle a use case like this, if I knew how to use JQ better.
I have tried various combinations of JQ's slurp, raw input, and raw output functions. All I accomplish is switching back and forth between everything escaped or my original problematic JSON. c is the only key whose value will ever have quotes within it.
There may also be another solution besides sed or JQ that addresses this in a wise way. A command-line solution is ideal, because I don't know C#, Java, or JavaScript. Python might be acceptable if there is simply no way to accomplish it with JQ.
Thank you for any help or ideas.
sed + jq solution:
sed -E 's/"/\\&/4g; s/\\"(,)?$/"\1/' input.json | jq -s '.'
The output:
[
{
"a": "value1",
"b": "value with \"quotes\"2",
"c": "value with \"more\" than one set of \"quotes\"3"
},
{
"a": "value4",
"b": "value with \"quotes\"5",
"c": "value with \"more\" than one set of \"quotes\"6"
},
{
"a": "value7",
"b": "value with \"quotes\"8",
"c": "value with \"more\" than one set of \"quotes\"9"
}
]

jq: selecting subset of keys from nested object

Input:
{"success": true, "results": {"a": …, "b": …, "c": …}}
Desired output, given I want to keep b:
{"success": true, "results": {"b": …}}
Things I tried:
$ jq 'del(select(.results.b | not))'
{"success": true, "results": {"a": …, "b": …, "c": …}}
# removes nothing from "results"
$ jq 'with_entries(select(.key == "success" or .key == "results.b"))'
{"success": true}
# nested comparison not understood; returns only "success"
Thanks!
Here is one solution:
.results |= {b}
Sample Run
$ jq -M '.results |= {b}' <<< '{"success":true, "results":{"a": "…", "b": "…", "c": "…"}}'
{
"success": true,
"results": {
"b": "…"
}
}
Try it online at jqplay.org
Another way using nodejs and shell :
Code :
$ node<<EOF
var obj = $(</tmp/file.json);
delete obj.results.a;
delete obj.results.c;
console.log(JSON.stringify(obj));
EOF
OUTPUT :
{"success":true,"results":{"b":"bbb"}}