Reputation: 8042
I have exported bookmarks from Firefox which in my case is quiet large JSON. I'm interested in the object with guid _0no-4e9woLW
in a JSON such as this one:
{
"foo": {
"bar": {
"zoo": {
"guid": "_0no-4e9woLW",
"title": "frontend",
"index": 3,
"dateAdded": 1614198626454000,
"lastModified": 1619505016472000,
"id": 16518,
"typeCode": 2,
"type": "text/x-moz-place-container",
"children": [
{
"guid": "2L7ZsYTM2RX0",
"title": "css child override parent style",
"index": 0,
"dateAdded": 1614198648005000,
"lastModified": 1614198648005000,
"id": 16519,
"typeCode": 1,
"type": "text/x-moz-place",
"uri": "https://www.google.com/search?client=firefox-b-d&q=css+child+override+parent+style"
},
{
"guid": "x3JHTAezzyI8",
"title": "css child parent inheritance",
"index": 1,
"dateAdded": 1614198648096000,
"lastModified": 1614198648096000,
"id": 16520,
"typeCode": 1,
"type": "text/x-moz-place",
"uri": "https://www.google.com/search?client=firefox-b-d&q=css+child+parent+inheritance"
}
]
}
}
}
}
Is it possible to get somehow full path up to "guid": "_0no-4e9woLW"
? guid keys are uniq in JSON. My goal is to type something like jq '["full path I've somehow previously obtained"]["children"].title'
And I will obtain:
css child override parent style
css child parent inheritance
Of course I could do this manually but I'm too lazy.
Upvotes: 0
Views: 456
Reputation: 1207
json2jqpath.jq file.json
.
.foo
.foo|.bar
.foo|.bar|.zoo
.foo|.bar|.zoo|.children
.foo|.bar|.zoo|.children|.[]
.foo|.bar|.zoo|.children|.[]|.dateAdded
.foo|.bar|.zoo|.children|.[]|.guid
.foo|.bar|.zoo|.children|.[]|.id
.foo|.bar|.zoo|.children|.[]|.index
.foo|.bar|.zoo|.children|.[]|.lastModified
.foo|.bar|.zoo|.children|.[]|.title
.foo|.bar|.zoo|.children|.[]|.type
.foo|.bar|.zoo|.children|.[]|.typeCode
.foo|.bar|.zoo|.children|.[]|.uri
.foo|.bar|.zoo|.dateAdded
.foo|.bar|.zoo|.guid
.foo|.bar|.zoo|.id
.foo|.bar|.zoo|.index
.foo|.bar|.zoo|.lastModified
.foo|.bar|.zoo|.title
.foo|.bar|.zoo|.type
.foo|.bar|.zoo|.typeCode
Shows guid
appears as a leaf in more than one unique path.
If there were only one you would be done
(assuming you knew the value existed)
with multiple paths you need to check that the value exists
and it is to your object of interest.
json2jqpath.jq file.json | grep guid
.foo|.bar|.zoo|.children|.[]|.guid
.foo|.bar|.zoo|.guid
Appending your given value to the paths returns objects containg them
jq '.foo|.bar|.zoo|.children|.[]|.guid="_0no-4e9woLW"' file.json
{
"guid": "_0no-4e9woLW",
"title": "css child override parent style",
"index": 0,
"dateAdded": 1614198648005000,
"lastModified": 1614198648005000,
"id": 16519,
"typeCode": 1,
"type": "text/x-moz-place",
"uri": "https://www.google.com/search?client=firefox-b-d&q=css+child+override+parent+style"
}
{
"guid": "_0no-4e9woLW",
"title": "css child parent inheritance",
"index": 1,
"dateAdded": 1614198648096000,
"lastModified": 1614198648096000,
"id": 16520,
"typeCode": 1,
"type": "text/x-moz-place",
"uri": "https://www.google.com/search?client=firefox-b-d&q=css+child+parent+inheritance"
}
jq '.foo|.bar|.zoo|.guid="_0no-4e9woLW"' file.json
{
"guid": "_0no-4e9woLW",
"title": "frontend",
"index": 3,
"dateAdded": 1614198626454000,
"lastModified": 1619505016472000,
"id": 16518,
"typeCode": 2,
"type": "text/x-moz-place-container",
"children": [
{
"guid": "2L7ZsYTM2RX0",
"title": "css child override parent style",
"index": 0,
"dateAdded": 1614198648005000,
"lastModified": 1614198648005000,
"id": 16519,
"typeCode": 1,
"type": "text/x-moz-place",
"uri": "https://www.google.com/search?client=firefox-b-d&q=css+child+override+parent+style"
},
{
"guid": "x3JHTAezzyI8",
"title": "css child parent inheritance",
"index": 1,
"dateAdded": 1614198648096000,
"lastModified": 1614198648096000,
"id": 16520,
"typeCode": 1,
"type": "text/x-moz-place",
"uri": "https://www.google.com/search?client=firefox-b-d&q=css+child+parent+inheritance"
}
]
}
Upvotes: 0
Reputation: 385506
To access a node by guid:
.. | objects | select( .guid == … )
So you'd use the following to get the title of _0no-4e9woLW
's children:
.. | objects | select( .guid == "_0no-4e9woLW" ) | .children[].title
To save a path:
path( … ) # As JSON
path( … ) | join(".") # As dotted path
Replace …
with an expression that returns the node(s) for which you want the path.
For example,
path( .. | objects | select( .guid == "_0no-4e9woLW" ) ) # [ "foo", "bar", "zoo" ]
path( .. | objects | select( .guid == "_0no-4e9woLW" ) ) | join(".") # "foo.bar.zoo"
To grab an object using its path:
getpath( … ) # From JSON
getpath( … | split(".") | map(tonumber? // .) ) # From dotted path
Replace …
with an expression that returns the previously saved path.
For example,
getpath( [ "foo", "bar", "zoo" ] ).children[].title
getpath( "foo.bar.zoo" | split(".") | map(tonumber? // .) ).children[].title
Upvotes: 1
Reputation: 26397
Using recurse
allows to get to the object easily :
jq -r 'recurse |
select(type=="object" and .guid == "_0no-4e9woLW")
.children[].title' firefox.json
Upvotes: 1
Reputation: 85530
Without the whole knowledge of the JSON, something like this should work when using path
family of functions i.e. getpath/1
( paths | select(.[-1] == "guid") ) as $p |
if getpath($p) == "_0no-4e9woLW" then getpath($p[:-1] + ["children"])[].title else empty end
The construct above means, select all those paths containing the leaf key named guid
and store them in a variable and filter only the path whose value turns out to be "_0no-4e9woLW"
. On the selected path, trim the child node($p[:-1]
removes "guid"
) and add the node "children"
and get the value at the new path constructed (using getpath/1
). Extract the .title
field from the JSON value
Upvotes: 2