Gron: Make JSON greppable
github.com
github.com
One warning to note is that gron burns RAM. I've killed 32GB servers working with 15MB JSON files. (I think gron -u is even worse, but my memory is a bit fuzzy here).
https://github.com/adamritter/fastgron as an alternative has been pretty good to me in terms of performance, I think both in speed and RAM usage.
a.b[0].c.d[0]: ... a.b[0].e[0].f: ...
https://github.com/adamritter/fastgron/blob/main/src/print_g...
And gron -u in theory should use less memory than gron-ifying a JSON, as you just have to fill a data structure in memory as you go.
You don't know the size, shape, or type of any of the levels in the data structure until you get to a line specifying one part of it. If you did, yep, it would be trivial!
If users[14] is a string, or there are 1500 users, the amount of memory usage to ungrok that line is exactly the same. Prove me wrong, I can't think of any way it would not be trivial, provided one uses the correct datastructures.
How big is it? All you know at this point is that it's at least 16 entries long. If the next line starts with `users[150]`, now it's 151 entries. Next line might make it 2000 entries long. You have no idea until you see the line.
> each is a map
But a map of what? `string -> object`? Ok, the next line is `users[15].flange[15]` which means your map is now `string -> (object|array)`.
Then the next line is `users[15].age = 15` and you've got `string -> (object|array|int)`. Each line can change what you've got and in Go this isn't a trivial thing to handle without resorting to `interface{}` (or `any`) all over the show and reflection to handle the management of the data structures.
> Prove me wrong, I can't think of any way it would not be trivial, provided one uses the correct datastructures.
All I can suggest is that you try to build `ungron` in Go and have it correctly handle disordered input. If you find a better way of doing it, I'd be happy to hear about it because I spent several months fighting Go in 2021-22 trying to optimise this without success.
It reads the file into memory once, then just goes through it only once, so it shouldn't need much more memory than the file size.
Also I put a lot of work into making fastgron -u fast, but you can grep the file directly as well.
I'm thinking of doing some marketing (for example a blog entry just to show what was the main learnings in I/O and memory management in order to achieve this speed).
`gron -u` is basically impossible to optimise unless you know the input is in "sorted" order (ie the order it comes out of `gron`, including the `json.a = {};` bits) in which case my code can handle that in almost no RAM also. But if it's not sorted or you're missing the `json.a = {};` lines, there's not a lot you can do since you have to hold the whole data structure in RAM.
Sure, but something is seriously wrong if a 15 MB JSON data structure uses more than 32 GB of RAM.
Which is 20 levels of unknown-sized and unknown-typed slices of slices of `any` in Go and that is not super-efficient, alas. It gets worse when you have maps of slices of maps etc. `fastgron` gets around this by being able to manage its own memory.
(`gron` can, however, reconstruct the output correctly if you shuffle the input. `fastgron` cannot. Which suggests to me it's maybe using the same 'output as we go' trick that my `gron` fork uses for its "input is sorted" mode which uses almost no RAM but cannot deal with disordered input.)
(`gron` could/should maybe indicate the maximum size of the slices and if they're a single type which would make things more efficient and I might add that to my fork.)
That sounds seriously like there is something wrong with the tool
`jq`: 1m26s 21G resident
`mygron -e --no-sort`: 18m14s 19M resident
`gron --no-sort`: 1m51s OOM killed at 54G resident
Oh dear
edit: Interestingly whilst doing this test, I piped the output into `fastgron -u` (39.5G resident) and `jq` rejected that. Will have to investigate further but it's a bit of a flaw if it can't rehydrate its own output into valid JSON.
I fixed the semicolon bug, but of course correctness is more important.
$ gron "https://api.github.com/repos/tomnomnom/gron/commits?per_page=1" | fgrep "commit.author"
json[0].commit.author = {};
json[0].commit.author.date = "2016-07-02T10:51:21Z";
json[0].commit.author.email = "mail@tomnomnom.com";
json[0].commit.author.name = "Tom Hudson";
And with jq: $ curl "https://api.github.com/repos/tomnomnom/gron/commits?per_page=1" | jq ".[].commit.author"
{
"name": "Tom Hudson",
"email": "mail@tomnomnom.com",
"date": "2022-04-13T14:23:37Z"
}
The jq version isn't greppable, as you can't do `| grep '.author.email'` for example.https://unix.stackexchange.com/questions/561460/how-to-print...
Truth to be told with jq you don't need to grap it, you can grab just emails directly. I find gron a lot more useful for grep -v, that is for filtering out the parts that you don't need. Super easy to clean up data.
You can then copy the path and use in jq with "yq".
With jq alone, you have to already understand the structure, which isn't always a given if you're combing through k8s manifests for instance.
def flat_json_keys:
[leaf_paths as $path | {"key": $path | map(if (type=="string") then (if (test("([?:\\W]+)")) then "['"+.+"']" else . end) else "["+tostring+"]" end) | join(".") | gsub(".\\[";"[") , "value": getpath($path)}] | from_entries;
def ukeys:
keys_unsorted;
Use like so: cat wat.json | jq flat_json_keysEdit: I found it. It was called pyx. https://www.xml.com/pub/2000/03/15/feature/index.html https://xmlstar.sourceforge.net/doc/UG/ch04s07.html
I'm looking at the test suite, trying to figure out how to get it to emit test failure details:
./makesure test_suite
mawk -f run_json_test_suit.awk
...
Successes: 186
Fails: 152Strange, should be much less failures: https://github.com/xonixx/gron.awk/blob/e5040a7b1384c5839dca...
Could you please file a bug with the details?
Looks like gron would be a nice addition to my workflow with JSON tasks.
https://pypi.org/project/jsonmason/
"maybe doing something depending on context for some nodes in a nested structure by using transforms or side-effects while iterating over the regularized representation of the structure's nodes"
It's a library but also includes CLI utilities that do the same as gron. Well, I hope without that memory ballooning problem described in sibling comments.
I am going to try to use it to make surgical edits to the terraform state file, in rare cases when I have to.
Some terraform providers would rather delete and recreate resource, while a simple edit would do the trick for me
Gron – Make JSON Greppable - https://news.ycombinator.com/item?id=25006277 - Nov 2020 (91 comments)
Gron: A command line tool that makes JSON greppable - https://news.ycombinator.com/item?id=16727665 - April 2018 (51 comments)
jq is awesome, and a lot more powerful than gron, but with that power comes complexity. gron aims to make it easier to use the tools you already know, like grep and sed.
I know grep, but sed is one of those I always have to look up whenever I have to escape a weird character or something.
Also the username of the author made me chuckle, bonus points for that.
JSON is already C-like https://www.json.org/json-en.html and jq uses dot-separated paths for chaining name/value accesses.