JSON delete specific keys from nested objects without knowing key names - json

I have a json file and want to delete some subkeys i don't need. Here is some part of the JSON file :
{
"peers":{
"swp1":{
"hostname":"Spine-01",
"remoteAs":65001,
"version":4,
"msgRcvd":452,
"msgSent":459,
"tableVersion":0,
"outq":0,
"inq":0,
"peerUptime":"00:19:15",
"peerUptimeMsec":1155000,
"peerUptimeEstablishedEpoch":1635674862,
"prefixReceivedCount":30,
"pfxRcd":30,
"pfxSnt":43,
"state":"Established",
"idType":"interface"
},
"swp2":{
"hostname":"Spine-02",
"remoteAs":65001,
"version":4,
"msgRcvd":452,
"msgSent":459,
"tableVersion":0,
"outq":0,
"inq":0,
"peerUptime":"00:19:14",
"peerUptimeMsec":1154000,
"peerUptimeEstablishedEpoch":1635674863,
"prefixReceivedCount":30,
"pfxRcd":30,
"pfxSnt":43,
"state":"Established",
"idType":"interface"
}
}
}
for example, i want to delete the "version" subkey, and i already tried this command
del(.peers.swp1.version, .peers.swp2.version)
and it worked well. But the thing is, the "swp1" and "swp2" are the interfaces and are something that can change their name, increase or decrease. So I need a command that works to delete the "version" subkeys no matter what the interface name is.

All you need is map_values and del.
.peers |= map_values(del(.version))
demo in jqplay

You can also use this syntax :
del(.peers[].version)|del(.memory)

Related

Use jq to remove top level module while retaining values

I'm trying to use jq in order to achieve the following -
With an input of:
{
"SomeValue": {
"x" : "y",
"a" : "b"
}
}
I'd like to be able to remove 'SomeValue' and return just the key/values below so that my output would look like:
{
"x" : "y",
"a" : "b"
}
I've tried various permutations of commands I've seen on the forum but either end up deleting the whole structure or nothing at all - thanks in advance for any help/pointers in the right direction.
If all you want is the content of .SomeValue, that's already exactly your filter:
jq '.SomeValue'
If this part is nested deeper, and you want to update that part while keeping the rest, use the update operator |= with .SomeValue on that context (with your small sample this is still just .):
jq '. |= SomeValue'

How to access the key of a jsoncpp Value

I kind of feel stupid for asking this, but haven't been able to find a way to get the key of a JSON value. I know how to retrieve the key if I have an iterator of the object. I also know of operator[].
In my case the key is not a known value, so can't use get(const char *key) or operator[]. Also can't find a getKey() method.
My JSON looks like this:
{Obj_Array: [{"122":{"Member_Array":["241", "642"]}}]}
For the piece of code to parse {"122":{"Member_Array":["241", "642"]}} I want to use get_key()-like function just to retrieve "122" but seems like I have to use an iterator which to me seems to be overkill.
I might have a fundamental lack of understanding of how jsoncpp is representing a JSON file.
First, what you have won't parse in JsonCPP. Keys must always be enclosed in double quotes:
{"Obj_Array": [{"122":{"Member_Array":["241", "642"]}}]}
Assuming that was just an oversight, if we add whitespace and tag the elements:
{
root-> "Obj_Array" : [
elem0-> {
key0-> "122":
val0-> {
key0.1-> "Member_Array" :
val0.1-> [
elem0.1.0-> "241",
elem0.1.1-> "642" ]
}
}
]
}
Assuming you have managed to read your data into a Json::Value (let's call it root), each of the tagged values can be accessed like this:
elem0 = root[0];
val0 = elem0["122"]
val0_1 = val0["Member_Array"];
elem0_1_0 = val0_1[0];
elem0_1_1 = val0_1[1];
You notice that this only retrieves values; the keys were known a priori. This is not unusual; the keys define the schema of the data; you have to know them to directly access the values.
In your question, you state that this is not an option, because the keys are not known. Applying semantic meaning to unknown keys could be challenging, but you already came to the answer. If you want to get the key values, then you do have to iterate over the elements of the enclosing Json::Value.
So, to get to key0, you need something like this (untested):
elem0_members = elem0.getMemberNames();
key0 = elem0_members[0];
This isn't production quality, by any means, but I hope it points in the right direction.

Extract all the values for a specific repeated key in JSON

I have a huge json file of about 4500 lines.
I wish to extract the value of all the keys named "value".
The levels of json paths are not same.
JSON Sample :
{
k1:v1,
k2:v2,
k3:v3,
k4:{
k5:v5,
k6:{
k7:v7,
value:"value1"
}
}
k8:v8,
value:"value2"
}
There are multiple such "value" tags.
Is there a way using jq to get all the values ?
Use recursive descent.
.. | objects | if has("value") then .value else empty end
Here is a slightly shorter variation of oguz ismail's answer which uses Optional Object Identifier .foo? and Alternative operator // along with recursive descent.
.. | .value? // empty
Example output (using corrected JSON Sample)
"value2"
"value1"
Note that this shortcut won't produce the same output if the "value" key may be null as // can't distinguish between a null "value" and a null produced by the ? operator when the "value" key is missing. It that's a concern then testing for the presence of the "value" key with has is better.
Try it online!

JSONPath Syntax when dot in key

Please forgive me if I use the incorrect terminology, I am quite the novice.
I have some simple JSON:
{
"properties": {
"footer.navigationLinks": {
"group": "layout"
, "default": [
{
"text": "Link a"
, "href": "#"
}
]
}
}
}
I am trying to pinpoint "footer.navigationLinks" but I am having trouble with the dot in the key name. I am using http://jsonpath.com/ and when I enter
$.properties['footer.navigationLinks']
I get 'No match'. If I change the key to "footernavigationLinks" it works but I cannot control the key names in the JSON file.
Please can someone help me target that key name?
Having a json response:
{
"0": {
"SKU": "somevalue",
"Merchant.Id": 234
}
}
I can target a key with a . (dot) in the name.
jsonPath.getJsonObject("0.\"Merchant.Id\"")
Note: the quotes and the fact that they are escaped.
Note not sure of other versions, but I'm using
'com.jayway.restassured', name: 'json-path', version: '2.9.0'
A few samples/solutions I've seen, was using singe quotes with brackets, but did not work for me.
For information, jsonpath.com has been patched since the question was asked, and it now works for the example given in the question. I tried these paths successfully:
$.properties['footer.navigationLinks']
$.properties.[footer.navigationLinks]
$.properties.['footer.navigationLinks']
$['properties']['footer.navigationLinks']
$.['properties'].['footer.navigationLinks']
properties.['footer.navigationLinks']
etc.
This issue was reported in 2007 as issue #4 - Member names containing dot fail and fixed.
The fix is not present in this online jsonpath.com implementation, but it is fixed in this old archive and probably in most of the forks that have been created since (like here and here).
Details about the bug
A comparison between the buggy and 2007-corrected version of the code, reveals that the correction was made in the private normalize function.
In the 2007-corrected version it reads:
normalize: function(expr) {
var subx = [];
return expr.replace(/[\['](\??\(.*?\))[\]']|\['(.*?)'\]/g, function($0,$1,$2){
return "[#"+(subx.push($1||$2)-1)+"]";
}) /* http://code.google.com/p/jsonpath/issues/detail?id=4 */
.replace(/'?\.'?|\['?/g, ";")
.replace(/;;;|;;/g, ";..;")
.replace(/;$|'?\]|'$/g, "")
.replace(/#([0-9]+)/g, function($0,$1){
return subx[$1];
});
},
The first and last replace in that sequence make sure the second replace does not interpret a point in a property name as a property separator.
I had a look at the more up-to-date forks that have been made since then, and the code has evolved enormously since.
Conclusion:
jsonpath.com is based on an outdated version of JSONPath and is not reliable for previewing what current libraries would provide you with.
You can encapsulate the 'key with dots' with single quotes as below
response.jsonpath().get("properties.'footer.navigationLinks'")
Or even escape the single quotes as shown:
response.jsonpath().get("properties.\'footer.navigationLinks\'")
Both work fine

MongoDB : Update Modifier semantics of "$unset"

In MongoDB, the update modifier unset works as follows:
Consider a Mongo DB Database db with a collection users. Users contain a Document, of the following format:
//Document for a user with username: joe
{
"_id" : ObjectId("4df5b9cf9f9a92b1584fff16"),
"relationships" : {
"enemies" : 2,
"friends" : 33,
"terminated" : "many"
},
"username" : "joe"
}
If I want to remove the terminated key, I have to specify the $unset update modifier as follows:
>db.users.update({"username":"joe"},{"$unset":{"relationships.terminated": "many"}});
My Question is, why do I have to specify the ENTIRE KEY VALUE PAIR for the $unset to work, instead of simply specifying:
>db.users.update({"username":"joe"},{"$unset":{"relationships.terminated"}});
Mon Jun 13 13:25:57 SyntaxError: missing : after property id (shell):1
Why not?
EDIT:
If the way to $unset is to specify the entire key value pair, in accordance with JSON specifications, or to add "1" as the value to the statement, why can't the Shell do the "1" substitution itself? Why isn't such a feature provided? Are there any pitfalls of providing such support?
The short answer is because {"relationships.terminated"} is not a valid json/bson object. A JSON object is composed of a key and a value, and {"relationships.terminated"} only has a key (or value, depends on how you look it).
Affortunately to unset a field in Mongo you do not need to set the actual value of the field you want to remove. You can use any value (1 is commonly used in Mongo docs) no matter the actual value of relationships.terminated:
db.users.update({"username":"joe"},{"$unset":{"relationships.terminated" : 1}});