This question already has answers here:
Using jq how can I replace the name of a key with something else
(2 answers)
Closed 4 months ago.
jq key assignment is not working.
I tried what was here for my use case.
Using jq how can I replace the name of a key with something else
in this case I want to change id to item_id`.
jq '.item[] | select(.closed == false) | select(.id == "1234") | .["id"] = .["item_id"] | .' data.json | less
the result does not error but "id" gets a value of null and there is not key called item_id. so there is something I am not getting right about assignment of the key.
You can just delete the old field using del, and add another one using object construction:
jq '.item[] | select(.closed == false and .id == "1234") | del(.id) + {item_id: .id}' data.json
Or use with_entries to "rename" the old field:
jq '.item[] | select(.closed == false and .id == "1234") | with_entries(select(.key == "id").key = "item_id")' data.json
Related
I'm trying to make request in jq:
cat testfile.txt | jq 'fromjson | select(.kubernetes.pod.memory.usage.bytes != null) .kubernetes.pod.memory.usage.bytes, ."#timestamp"'
My output is:
"2019-03-15T00:24:21.733Z"
"2019-03-15T00:25:10.169Z"
"2019-03-15T00:24:47.908Z"
105889792
"2019-03-15T00:25:04.446Z"
34557952
"2019-03-15T00:25:04.787Z"
How to delete excess dates?
For example output only:
105889792
"2019-03-15T00:25:04.446Z"
34557952
"2019-03-15T00:25:04.787Z"
You just need to add a pipe after select :
cat testfile.txt | jq 'fromjson | select(.kubernetes.pod.memory.usage.bytes != null) | .kubernetes.pod.memory.usage.bytes, ."#timestamp"'
Here's a DRYer (as in dry) solution:
.["#timestamp"] as $ts | .kubernetes.pod.memory.usage.bytes // empty | ., $ts
Note that this particular use of // assumes that you wish to treat null, false, and a missing key in the same way. If not, you can still use the same idea to stay DRY.
I have a JSON with dynamic data and not sure how I can retrieve data with JQ.
My JSON is:
{
"RuntimeSources":{
"env-name-DYNAMIC":{
"the-dynamic-value-i-need-to-get":{
"url":""
}
}
},
"DeploymentId":147,
"Serial":158
}
'env-name-DYNAMIC' is dynamic and 'the-dynamic-value-i-need-to-get' is the same.
The json structure is always the same. How can I get 'the-dynamic-value-i-need-to-get'? Also I may need to retrieve 'env-name-DYNAMIC'
Use the keys[] attribute
.RuntimeSources | keys[]
and also
.RuntimeSources | keys[] as $k | .[$k] | keys[]
Since you had also mentioned, the structure doesn't change, you can just select the paths that contains 3 levels
paths | select( length == 3 ) | .[1]
paths | select( length == 3 ) | .[2]
I managed to get it with:
jq '.RuntimeSources | .[] | keys'
Not sure if it's the best solution, but did the trick.
I've encountered some difference between null and nothing, can somebody explain it? As in most languages null is considered/used to represent nothing.
The select is documented to return no output. And adding(ie. +) null to X yields X. Now consider these demonstrative examples(takes no input):
adding nothing
here we have empty object, which we update with nothing:
{} | . |= . + ({} | select (.foo == 123))
which results in
null
adding null
same template but with alternative operator to substitute nothing to null:
{} | . |= . + ({} | select (.foo == 123)//null)
which results in
{}
Can someone explain the difference nothing vs null?
null is just a regular JSON value; and conceptually, it is totally different from the absence of a value, i.e, what you termed nothing. Take a look at these for example (empty is a filter that returns nothing):
$ jq -n '[null] | length'
1
$ jq -n '[empty] | length'
0
That {} + null returns {} back, and that {} | . |= empty does exactly what del(.) does are merely design choices.
Hello i managed to create this jq filter .profiles | recurse | .gameDir? | if type == "null" then "" else . end | scan("{REPLACE}.*") | sub("{REPLACE}"; "{REPLACESTRINGHERE}"). it succesfully replaces what i want (checked at jqplay.org) but now i'd like to print the full json and not just the modified strings
Adapting your query:
.profiles |= walk( if type == "object" and has("gameDir")
then .gameDir |=
(if type == "null" then "" else . end
| scan("{REPLACE}.*") | sub("{REPLACE}"; "{REPLACESTRINGHERE}"))
else .
end )
(This can easily be tweaked for greater efficiency.)
If your jq does not have walk, you can google it (jq “def walk”) or snarf its def from the jq FAQ https://github.com/stedolan/jq/wiki/FAQ
walk-free approach
For the record, here's an illustration of a walk-free approach using paths. The following also makes some changes in the computation of the replacement string -- notably it eliminates the use of scan -- so it is not logically equivalent, but is likely to be more useful as well as more efficient.
.profiles |=
( . as $in
| reduce (paths | select(.[-1] == "gameDir")) as $path ($in;
($in | getpath($path)
| if type == "null" then ""
else sub(".*{REPLACE}"; "{REPLACESTRINGHERE}")
end) as $value
| setpath($path; $value) ))
How to recursively delete all keys that match a given pattern?
I have following jq config, but it doesn't seem to work:
walk( if (type == "object" and (.[] | test('.*'))) then del(.) else . end)
A robust way (with respect to different jq versions) to delete all keys matching a pattern (say PATTERN) would be to use the idiom:
with_entries(select( .key | test(PATTERN) | not))
Plugging this into walk/1 yields:
walk(if type == "object" then with_entries(select(.key | test(PATTERN) | not)) else . end)