How to filter an array of objects using multiple conditions in JSONPATH? - jsonpath

I am using jsonpath library (https://github.com/json-path/JsonPath) in Go, and I need to process a JSON object and filter from an array of objects, the objects which match any of the multiple criteria (OR conditions). I have been unsuccessful in getting the filter to work correctly and hoping that someone can help me in the right direction. I am providing a simplified example below.
Let us assume I have the following JSON Object.
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "iPhone",
"number": "123-4567-8888"
},
{
"type" : "home",
"number": "123-4567-8910"
},
{
"type" : "mobile",
"number": "123-4567-1233"
}
]
}
I would like filter all phone numbers (phoneNumbers) which are of type "home" or "iPhone". I have used the following expression, but it results in an empty array:
$.phoneNumbers[?(#.type=='home' || #.type == 'iPhone')]
Please see this JSONPath expression tester below. I have saved the JSON here, but it doesn't keep the JSONPath expression, and it will need to be pasted manually.
JSONPath Expression Tester

Related

JsonPath For multiple object

I want to know the name who purchased items "abc" and "def" from the bellow json data.
(Expected result is "tom")
Please tell me how to do using JsonPath.
[
{
"name": "tom",
"purchased": [
{
"name": "abc"
},
{
"name": "def"
}
]
},
{
"name": "bob",
"purchased": [
{
"name": "xyz"
}
]
}
]
If you are doing this in Java you could select the name of the buyer like this:
$..[?(#.purchased && #..name contains 'abc' && #..name contains 'def' )].name
In JavaScript, you can use this a query like this:
$.[?(#.purchased && #.purchased.some(e => e.name==='abc') && #.purchased.some(e => e.name==='def') )].name
Both queries use a similar approach:
We filter for a purchased-property, then use a function to search the keys in the map for certain values
Jayway's JsonPath offers a contains function to do so;
In JavaScript we leverage script evaluation to search the map/dict for our key/values
So, the .some() is not a JsonPath function but some modern JavaScript (:D).
This is kind of a workaround in both cases but it gets the job done.
You can test both online here. Select the tab JayWay and click Go for the first query, switch to tab Goessner to run the JavaScript sample (you can run the second here as well).

modify nested object but maintain the full object after

I need to modify an element --an array-- (e.g.: "group-xyz") within a nested object in a JSON tree using JQ but once that's done then I need the entire object back with the modified data.
The goal is to update a JSON tree and save it in full.
e.g.: add array element, empty array, etc.
{
"group-abc": {"users": ["tina.turner"]},
"group-def": {"users": ["someone.else"]},
"group-xyz": {"users": ["that.thing"]
}
Then I am interested in returning an object like this:
{
"group-abc": {"users": ["tina.turner"]},
"group-def": {"users": []},
"group-xyz": {"users": ["that.thing","well.done"]
}
I have changed my requirements to fit a more complex form. To add a user to any of these groups' users this is what I did:
jq '. |= map( if ( .group=="abc") then .users+=["final.answer",] else . end)' source.json
which produced a result
[
{
"group": "abc",
"users": [
"user1",
"user2",
"final.answer"
]
},
{
"group": "def",
"users": [
"user4",
"user5"
]
}
]

How do I get a list of all properties in a JSON document?

I have a dynamic JSON document but for the sake of this question, imagine it resembles the following:
{
"name": "Jungle Gym",
"age": 25,
"favorite_color": "#ffa500",
"gender": "male",
"location": {
"city": "Seattle",
"state": "WA",
"citystate": "Seattle, WA"
},
"pets": [
{
"type": "dog",
"name": "Foo",
"food": [
"chicken",
"beef",
"fish"
]
},
{
"type": "cat",
"name": "Bar"
}
]
}
How do I get a list of all property names in the document? I can get the top level property names ("name", "age", "favorite_color", "gender", "location", "pets") but I need to get all property names down to "location.state" or "pets.food" and, if the properties / objects exist, even deeper.
I started using the following:
var model = JsonConvert.DeserializeObject<JObject>(json);
foreach (JProperty property in model.Properties())
{
if (property.Value.Type == JTokenType.Object)
{
foreach (var tmp in property.Children())
{
Console.WriteLine(tmp.SelectToken().);
}
}
}
but cannot seem to navigate into the objects beyond the top level to get the next level of properties (location properties, e.g.). Ideally, I'd like the list of derived property names to include the full path to the property, e.g., location.city, location.state, etc., instead of just the property name, e.g. city, state.
How can I get a list of all properties in a JSON document with potentially various levels of nesting?
In order to get all the keys in Json string (all levels), you could use Descendants and Path properties to fetch the details.
var data = JObject.Parse(jsonString);
var result = data.Descendants()
.OfType<JProperty>()
.Select(f=>Regex.Replace(f.Path,#"\[[0-9]\]",string.Empty))
.Distinct();
Please note the Regex is used to replace all the indices that might result due to pets list.
Output,

Complex object in a query string

How can I have this structure in a query string?
"properties": {
"list": [
{
"label": "bye",
"value": "world"
},
{
"label": "hello",
"value": "mars"
}
]
}
I've tried it with properties[][list][label]=bye&properties[][list][value]=world&properties[0][label]=hello&properties[0][value]=mars and also with properties[][list][label]=bye&properties[][list][value]=world&properties[][list][label]=hello&properties[][list][value]=mars, none of them worked. I built them in php with http_build_query.
I need to have this structure in a query string because I have to send the data along with some other stuff with POST to a PHP site.
I see two errors in your query string:
properties is an object, so there's no need to use [] to add elements.
list is an array, so you must use numeric indexes in the query string.
The correct query string is:
?properties[list][0][label]=bye
&properties[list][0][value]=world
&properties[list][1][label]=hello
&properties[list][1][value]=mars
(multi-lined for readability)

How to filter a non-array in JsonPath

Using the following JSON (from http://jsonpath.com):
{
"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"
}
]
}
I would like to get the root object only if firstName is John.
I have tried these inputs and many other similar ones:
$.[?($.firstName == 'John')]
$.[?($.'firstName' == 'John')]
$.[?(#.firstName == 'John')]
$[?($.firstName == "John")]
It seems as though filtering is only intended for arrays so this is an unsupported function. Does someone know a way to do this in Json.NET, or confirm that it's not possible and maybe point me to a library which supports the above?
I'm using F# but that's not important because F# is compatible with C#, .NET and NuGet packages.
JSON path is intended to locate data in a JSON object and not to perform some processing or testing on that data. The filter notation is used to identify an item in an array with the purpose of returning that data or some part of it. Having objects in an array means that there may be many properties with the same name that have to be filtered by some other means in order to select a subset of them.
Using filter notation on an object property is not the same thing. There can only be one property in an object with a particular name so stating that name is sufficient to identify it uniquely. You can easily achieve the effect you require by getting $.firstName and then testing separately for the value "John"

Resources