JPath for partial query match - json

I'm trying to learn json jpath query. I have successfully been able to return data based on exact searches.
For example at the site: https://jsonpath.com/ I can successfully retrieve the type of phone based on phone number:
JSON
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "iPhone",
"number": "0123-4567-8888"
},
{
"type" : "home",
"number": "0123-4567-8910"
}
]
}
Query
$.[?(#.number== '0123-4567-8888')].type
However I can't find any examples that show me how to match a partial search result. I'm trying to write a query where I provide just "0123" and hence get back both "home" and "iPhone" returned as results.How can I do this?

You can use =~ match filter operator which allows providing a regular expression instead of strict value so given you amend your query like:
$.phoneNumbers[?(#.number=~/.*0123.*/)].type
you will get both types as the result:
More information: JMeter's JSON Path Extractor Plugin - Advanced Usage Scenarios

Related

How to escape "#" when reading from a JSON response?

Let's say I have below sample JSON response from which I want to extract value for "#type":
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"phoneNumbers": [
{
"#type" : "iPhone",
"number": "0123-4567-8888"
},
{
"#type" : "home",
"number": "0123-4567-8910"
}
]
}
Validated using:- http://jsonpath.com/
This works for "number":
$.phoneNumbers.[number]
But cannot get value for "#type":
$.phoneNumbers.[#type]
Tried multiple ways but no luck.
Thanks!
Edits:- added another value in the array for "home", now indexing logic [0,1] doesn't work. Even tried with [:] to fetch all values, but no luck.
You can read in this documentation:
Please note, that the return value of jsonPath is an array, which is
also a valid JSON structure.
So basically it always returns an array.
var phoneTypes = jsonPath(json,"$.phoneNumbers.[#type]");
result
["iPhone","home"]
if you want one phone you have to use phoneTypes[0] for iPhone
but I higly recommend you to fix your json using this code
var fixedJson= JSON.parse(JSON.stringify(json).replaceAll("\"#type\"","\"type\"" ));
in this case you can use the real search
var homePhone = jsonPath(fixedJson,"$.phoneNumbers[?(#.type =='home')]")[0].number;
output
0123-4567-8910

Setting a value into a json using jsonPath in karate

I have the below Json File(Test.json) read into a variable in karate
TestInput.json:
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "Mobile",
"number": "0123-4567-8888"
},
{
"type" : "home",
"number": "0123-4567-8910"
}
]
}
I intend to change the value of Mobile number within my karate code and use the Json as my request with the following lines
Karate Code:
* def reqJson = read('TestInput.json')
* karate.set('reqJson','$.phoneNumbers[?(#.type=="Mobile")].number',"999999999")
Then print reqJson
The output of the print statement doesn't have the json updated with the number for Mobile.
Alternatively, I've also used the below line to set the variable, but this hasn't worked either:
* set reqJson.phoneNumbers[?(#.type=="Mobile")].number = "99999999"
Is this possible via Karate? If Yes can someone please point me to the place where I'm going wrong or an alternative approach to achieve my scenario.
Thanks.
You can't use JsonPath to mutate. Directly access the path or use a map() operation: https://github.com/karatelabs/karate#json-transforms
This is just one example assuming the JSON is in a variable called body. Take some time to get used to JSON transforms.
* body.phoneNumbers = body.phoneNumbers.map(x => { x.number = '999'; return x })

How can i match fields with wildcards using jq?

I have a JSON object of the following form:
{
"Task11c-0-20181209-12:59:30-65611" : {
"attributes" : {
"configname" : "Task11c",
"datetime" : "20181209-12:59:30",
"experiment" : "Task11c",
"inifile" : "lab1.ini",
"iterationvars" : "",
"iterationvarsf" : "",
"measurement" : "",
"network" : "Manhattan1_1C",
"processid" : "65611",
"repetition" : "0",
"replication" : "#0",
"resultdir" : "results",
"runnumber" : "0",
"seedset" : "0"
},
......
},
......
"Task11b-12-20181209-13:03:17-65612" : {
....
....
},
.......
}
I reported only the first part, but in general I have many other sub-objects which match a string like Task11c-0-20181209-12:59:30-65611. They all have in common the initial word Task. I want to extract the processid from each sub-object. I'm trying to use a wildcard like in bash, but it seems not to be possible.
I also read about the match() function, but it works with strings and not json objects.
Thanks for the support.
Filter keys that start with Test and get only the attribute of your choice using the select() expression
jq 'to_entries[] | select(.key|startswith("Task")).value.attributes.processid' json

Is there any way to preserve the order while generating patch for json files ?

I am new to Json stuff i.e. JSON PATCH.
I have scenario where I need to figure out between two version of Json files of same object, for that I am using json-patch-master.
But unfortunately the patch generated interpreting it differently i.e. the order differently hence getting unexpected/invalid results.
Could anyone help me how to preserve the order while generating Json Patch ?
**Here is the actual example.
Original Json file :**
[ {
"name" : "name1",
"roolNo" : "1"
}, {
"name" : "name2",
"roolNo" : "2"
}, {
"name" : "name3",
"roolNo" : "3"
}, {
"name" : "name4",
"roolNo" : "4"
} ]
**Modified/New Json file: i.e. removed 2nd node of original file.**
[ {
"name" : "name1",
"roolNo" : "1"
}, {
"name" : "name3",
"roolNo" : "3"
}, {
"name" : "name4",
"roolNo" : "4"
} ]
**Patch/Diff Generated :**
[ {"op":"remove","path":"/3"},
{"op":"replace","path":"/1/name","value":"name3"},
{"op":"replace","path":"/1/roolNo","value":"3"},
{"op":"replace","path":"/2/name","value":"name4"},
{"op":"replace","path":"/2/roolNo","value":"4"}]
Very time I generate Diff/Patch it is giving different path/diff results.
And moreover the interpretation is different i.e. order is not preserving.
**Is there any way to get expected results i.e. [ {"op":"remove","path":"/1"} ] , in other words generated a patch/diff based some order so will get what is expected. ?
How to handle this kind of scenario ?**
Please help me.
Thank you so much.
~Shyam
We are currently working on this issue in Starcounter-Jack/JSON-Patch.
It seems to work nice with native Array.Observe- http://jsfiddle.net/tomalec/p4s7aw96/.
Try Starcounter-Jack/JSON-Patch issues/65_ArrayObserve branch
we will release it as new version once shim and performance will be checked.
Feel free to add you comments at JSON-Patch issue board

MongoDB AND Comparison Fails

I have a Collection named StudentCollection with two documents given below,
> db.studentCollection.find().pretty()
{
"_id" : ObjectId("52d7c0c744b4dd77efe93df7"),
"regno" : 101,
"name" : "Ajeesh",
"gender" : "Male",
"docs" : [
"voterid",
"passport",
"drivinglic"
]
}
{
"_id" : ObjectId("52d7c6a144b4dd77efe93df8"),
"regno" : 102,
"name" : "Sathish",
"gender" : "Male",
"dob" : ISODate("2013-12-09T21:05:00Z")
}
Why does the below query returns a document when it doesn't fulfil the criteria which I gave in find command. I know it's a bad & stupid query for AND comparison. I tried this with MySQL and it doesn't return anything as expected but why does NOSQL makes problem. I hope it's considering the last field for comparison.
> db.studentCollection.find({regno:101,regno:102}).pretty()
{
"_id" : ObjectId("52d7c6a144b4dd77efe93df8"),
"regno" : 102,
"name" : "Sathish",
"gender" : "Male",
"dob" : ISODate("2013-12-09T21:05:00Z")
}
Can anyone brief why does Mongodb works this way?
MongoDB leverages JSON/BSON and names should be unique (http://www.ietf.org/rfc/rfc4627.txt # 2.2.) Found this in another post How to generate a JSON object dynamically with duplicate keys? . I am guessing the value for 'regno' gets overridden to '102' in your case.
If what you want is an OR query, try the following:
db.studentCollection.find ( { $or : [ { "regno" : "101" }, {"regno":"102"} ] } );
Or even better, use $in:
db.studentCollection.find ( { "regno" : { $in: ["101", "102"] } } );
Hope this helps!
Edit : Typo!
MongoDB converts your query to a Javascript document. Since you have not mentioned anything for $and condition in your document, your query clause is getting overwritten by the last value which is "regno":"102". Hence you get last document as result.
If you want to use an $and, you may use any of the following:
db.studentCollection.find({$and:[{regno:"102"}, {regno:"101"}]});
db.studentCollection.find({regno:{$gte:"101", $lte:"102"}});