GPath on nested objects - java

I'm not sure what I'm doing wrong here and I'm having a hell of a time with getting this to work properly. Using this JSON:
{
"books": [
{
"category": "reference",
"author": {
"name": "Nigel Rees",
"age": 45
},
"title": "Sayings of the Century",
"price": 8.95,
"tax": 7.00
},
{
"category": "reference",
"author": {
"name": "Evelyn Waugh",
"age": 30
},
"title": "A cheap book",
"price": 6.00,
"tax": 3.00
}
]
}
I'm not able to extract the books where the authors age is 45, for example. I've tried things like the following (with the books document root set)
findAll {it.author.age == 45}
findAll {it.author}.findAll {it.age == 45}
findAll {it.author}*.each {it.age == 45 }
I still get back all of the records that have an age item. It can be any arbitrary object, it might not have an author record, etc. And I want the root book object returned.
I feel like there's something really obvious I'm missing, but the docs seem to only cover one level of key-values. Maybe it doesn't support it?
Thanks!

here is it
books.findAll{it.author.age==45}
It's not working your way (findAll {it.author.age == 45}) because you work from the root, and 'it' variable returns 'books' object, which has no field 'author'.

Related

JSONPath: Get root array object using filter of child value

Im trying to get JSONPath expression to filter my JSON and get whole sport object using value of child array.
I have following JSON:
[{
"name": "Soccer",
"regions": [{
"name": "Australia",
"leagues": [{
"name": "Australia league",
"inplay": 5,
}
]
}
]
}, {
"name": "Tennis",
"regions": [{
"name": "Germany",
"leagues": [{
"name": "Germany league",
"inplay": 0,
}
]
}
]
}
]
I need to get whole sport object where "inplay == 0" using JsonPath expression.
Result should look like that:
{
"name": "Tennis",
"regions": [{
"name": "Germany",
"leagues": [{
"name": "Germany league",
"inplay": 0,
}
]
}
]
}
Regions and Leagues count can be > 1
Therefore $[?(#.regions[0].leagues[0].inplay == 0)] is not suitable
Tried $[?(#.regions[*].leagues[*].inplay == 0)] but it doesnt work
This works for me
$[?(#.regions[0].leagues[0].inplay == 0)]
Since this is not directly supported (as of now) in JayWay JSONPath we leverage contains as a workaround:
$[?(#.regions..inplay contains '0')]
Note: It may look like contains would work similar to a 'like' operator or instr function but this is not the case here. If the inplay value contains a 0, e.g. 10 it would not pull the record (according to my tests;)

JsonPath: How to get the whole tree except one node

everyone.
My question is quite simple, I think.
My use case:
Jenkins receives a huge JSON payload from a Gitlab WebHook (more than 2500 lines). I want to get rid of a specific node with more than 2000 lines. The JSON I get is so big that Jenkins is unable to parse it correctly so I want to remove a node I don't need.
Assume the sample tree in the documentation page:
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
How can I get the whole tree except one? For example, if I want to get everything but the book node ...
{
"store": {
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
I more or less understand the filters feature, and I assume I need to figure out a proper filter but it seems they are only useful to search nodes based on some criteria. I'm not sure if they are useful to remove elements based on filtering conditions.
Thanks so much for your help.
JSON Path is a tool for querying, not manipulation. You're not going to be able to alter the input value with it. You need another tool.
I'd suggest looking at something like https://jsonnet.org/ which is designed for template-based transformations and generation.

how to compare each element in array?

{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
]
}
}
The following is my case:
author=='Nigel Rees'.price < author=='Evelyn Waugh'.price
My query expression: $.store.book[?($.store.book[?(#.author == 'Nigel Rees')].price < $.store.book[?(#.author == 'Evelyn Waugh')].price)]
I hope it will return the following result:
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
}
What is the correct expression?
Ordinarily, to iterate over the items in an array and perform a comparison, you'd need to use a filter selector:
$.store.books[?(#.price<12.99)]
But this doesn't allow you to compare items against each other. Within that expression, you should (may depend on the library you're using) be able to use the $ to refer back to the JSON root. This would allow you to make a comparison against a particular item:
$.store.books[?(#.price<$.store.books[1].price)]
This compares all of the book prices against the price of the second book in the array. I think this is the closest you're going to get with JSON Path.
We're currently working on a specification for JSON Path to define an official syntax and feature set. Feel free to open an issue (and link to this question) to request "multiple iterator" support so that items can be compared against each other.

How to design data for complex recursive entities for persistence?

I was assuming that I have an entity as "Person".
{
"UnqIdr": 125,
"FrstNm": "Mark",
"LastNm": "Antony",
"Gndr": "Male",
"DtOfBirth": "06-09-2020",
"CtctDtls": {
"Addr": [
{
"UnqIdr": "10001",
"Ln1": "Street name",
"Ln2": "Block Number",
"Ln3": "Ward number",
"Cty": "New York",
"ZipCd": "60034",
"Stat": "New Jersey",
"Ctry": "North America",
"IsPrmy": true
}
],
"PhneNb": [
{
"Nm": "Principal",
"CtryCd": "+1",
"Nb": "1234567890",
"IsPrmy": true
}
],
"Email": "abc#def.com",
"CtctURL": "www.def.com",
"SclMdia": {
"FacebookURL": "www.facebook.com/def",
"LinkedInURL": "www.linkedin.com/us/def",
"TwitterURL": "www.twitter.com/3634556"
}
},
"IdntyProof": [{
"UnqIdr": 16537,
"Ctry": "India",
"IdntyTp": 6548,
"IdntyIdr": "INYHGB3462",
"IsVerified": true,
"VldFrm": "16-01-2000",
"VldTill": "4-12-2023"
}],
"PrsnlIdnty": {
"BldGrp": "A",
"Id":[{
"Nt": "Mole in right arm"
}]
},
"Ethncty": "Nadar",
"Rlgn": "Hindu",
"Ntnlty": "Indian",
"PrvsNtnlty": [{
"Ntnlty": "Indian",
"IdntyProof": [{
"UnqIdr": 16537,
"Ctry": "India",
"IdntyTp": 6548,
"IdntyIdr": "INYHGB3462",
"IsVerified": true,
"VldFrm": "16-01-2000",
"VldTill": "4-12-2023"
}]
}],
"MrtlSts": "Married",
"Rltsh": [{
"RltshTp": "Spouse",
"UnqIdr": 134
},{
"RltshTp": "Divorcee",
"UnqIdr": 130
}]
}
However, the same information applies to an Employee, Customer and few more.
Structure of employee might be
{
"UnqIdr": 125,
"Department": "Chem Lab",
"Person": {...}
}
However, when building the logic, we found an employee can also be a customer. Hence we thought of bundling as follows:
{
//person-info
"employee-info": {},
"customer-info": {}
}
Now the problem comes up[ how to query with employee-info or customer-info.
I know it is data design; however, we are using Java 11 and Spring JPA for the same.
Additionally, which would be effective ways to design the solution. Even using NoSQL database is open for discussion.
Look for data normalization with relational databases.
A simple solution is to store Person object in a different table and assigning it a personId field.
So the employee structure becomes:
{
"UnqIdr": 125,
"Department": "Chem Lab",
"PersonId": 420
}
Relational databases are made for such data domains (eventual consistency for people....... no please).
Look here for some database design involving CUSTOMER and EMPLOYEE:
https://www.oracletutorial.com/getting-started/oracle-sample-database/
Now, you can still have Java inheritance regarding these People common attributes.

Remove selected nodes from a JSON stream

I need to serve JSON from from my backend to the user. But before sending it over the wire I need to remove some data because it's confidential, every element who's key starts with conf_.
Assume I have the following JSON source:
{
"store": {
"book": [
{
"category": "reference",
"conf_author": "Nigel Rees",
"title": "Sayings of the Century",
"conf_price": 8.95
},
{
"category": "fiction",
"conf_author": "Evelyn Waugh",
"title": "Sword of Honour",
"conf_price": 12.99
},
{
"category": "fiction",
"conf_author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"conf_price": 8.99
},
{
"category": "fiction",
"conf_author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"conf_price": 22.99
}
],
"bicycle": {
"color": "red",
"conf_price": 19.95
}
},
"expensive": 10
}
Since the structure of the soruce JSON may vary (is not known), I need a way to identify the elements to remove by a pattern based on the key name (^conf_).
So the resulting JSON should be:
{
"store": {
"book": [
{
"category": "reference",
"title": "Sayings of the Century"
},
{
"category": "fiction",
"title": "Sword of Honour"
},
{
"category": "fiction",
"title": "Moby Dick",
"isbn": "0-553-21311-3"
},
{
"category": "fiction",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8"
}
],
"bicycle": {
"color": "red"
}
},
"expensive": 10
}
Since my source JSON will have 1m+ entries in the books array where every entry will have 100+ fields (child objects), I'm looking for some stream / event based approach like StAX rather then parsing the whole JSON into a JSONObject for manipulation for performance and resource reasons.
I looked at things like Jolt, JSONPath and JsonSurfer but these libraries did me get anywhere so far.
Can anyone provide some details on how my use case could be implemented best?
Regards!
You can use Jackson's Streaming API which can be used to parse huge JSON upto even giga bytes of size.It can be used to process huge files without loading them completely in memory.It allows get the data you want and ignore what you don't want also
Read more: http://wiki.fasterxml.com/JacksonStreamingApi

Categories