Use JsonPath to read nested array properties - java

[
{
"path": "test",
"resources": [
{
"name": "testfile"
}
]
},
{
"path": "test-1",
"resources": [
{
"name": "testfile-1"
}
]
}
]
Given a json like above, is it possible to read it in following format using jsonPath?
[
{
"path": "test",
"name": "testfile"
},
{
"path": "test-1",
"name": "testfile-1"
}
]
Its safe to assume that resources array will always be size 1.
I tried $.[*]['path', ['resources'][0]['name']] but it does not show the value of path.

As mentioned, this cannot be done with JSONPath; selecting items from different levels and recombining them into new array elements does not work, you need a JSON transformer like Jolt instead.
There are different ways but you could use shift transformer like shown below to get the desired output:
[
{
"operation": "shift",
"spec": {
"*": {
// Grab the value of clientName, and write it to
// bookMap. whatever is at clientId
"#path": "[&].path",
"#resources[0].name": "[&].name"
}
}
}
]
Try it online with your own input here.

Related

How to remove an attribute from RequestSpecification/FilterableRequestSpecification body?

Dears,
I am working on creating a simple method which will take String argument which will be a path or other kind "pointer" to attribute/s in JSON and this method will remove those attribute/s.
My problem is I can find values of those attribute/s using JsonPath, but I can't find methods in rest assured (or other libraries) which could remove/delete attributes by given path.
JSON is already added earlier so i need to pull him from RequestSpecification or FilterableRequestSpecification object ex.
RequestSpecification rs = *objFromContext*;
FilterableRequestSpecification frs= (FilterableRequestSpecification) rs;
frs.getBody();
I've tried to work with JSONObject class and remove() but it doesn't work on complex JSONs.
given example JSON
{
"created": "string",
"updated": "string",
"items": [
{
"code": "TEST",
"nested": {
"code": "test",
"name": "name",
"other": [
{
"code": "TEST",
"name": "myName",
"quantity": 1
}
]
},
"itemsProperties": [
{
"code": "value1",
"name": "name",
"value": 123
}
]
},
{
"code": "TEST",
"nested": {
"code": "test",
"name": "name",
"other": [
{
"code": "TEST",
"name": "myName",
"quantity": 1
}
]
},
"itemsProperties": [
{
"code": "value2",
"name": "name",
"value": 123
}
]
}
],
"timer": {
"startDate": "2015-01-01",
"endDate": "2021-01-02"
},
"id": "myId"
}
using JsonPath jp = JsonPath.from(httpRequest.getBody().toString());
and then jp.get(items.itemsproperties.code) i can find value1 and value2.
I stuck in this point: How to remove those attributes from sended body?
I know i can convert body into JSONObject and then go field after field conversion between getJSONArray and GetJSONOBject and remove those fields, but i would like to make this metod much more universal.
Is this possible?
If you want to manipulate json in Rest-Assured JsonPath, then the answer is No. You can't do that. JsonPath help you to extract value from json, that's it, no more.
You have to use different libraries to remove key-value pair.
For example: using JsonPath Jayway
DocumentContext parse = JsonPath.parse(body);
parse.delete("$..itemsProperties..code");
System.out.println(parse.jsonString());

How to assign to a new array an array of objects?

I can't figure out how I would do the ff.
I have the ff. Payload
{
"code": null,
"message": null,
"recCtrlOut": {
},
"acctSumm": [
{
"acctBasic": {
"acctType": "SV",
"acctId": "123",
},
"acctBasic": {
"acctType": "SV",
"acctId": "321",
}
}
]
}
And I just want to get the acctId params and assign it to a new plain array of accountIds. How do I do it in Spring/Java?. Thanks
Try using json path. Library can be found here. E.g. say you had json like this:
{
"code": null,
"message": null,
"recCtrlOut": {
},
"acctSumm": [
{
"acctBasic": {
"acctType": "SV",
"acctId": "123"
}
},
{
"acctBasic": {
"acctType": "SV",
"acctId": "321"
}
}
]
}
Actual code would be something like:
List<String> ids = JsonPath.read(json, "$.acctSumm[*].acctBasic.acctId");
The above list will now hold:
["123","321"]
If you wanna learn json path syntax, you could try using this online tool. Here is also a guide to help you get started with json path.

Jolt Transform JSON Spec

I need to transform below Input JSON to output JSON and not sure about how to write spec for that. Need to re-position one field ("homePage") as a root element. Any help or suggestion would be appreciated.
Input JSON :
[{
"uuid": "cac40601-ffc9-4fd0-c5a1-772ac65f0587",
"pageId": 123456,
"page": {
"indexable": true,
"rootLevel": false,
"homePage": false
}
}]
Output JSON :
[{
"uuid": "cac40601-ffc9-4fd0-c5a1-772ac65f0587",
"pageId": 123456,
"homePage": false,
"page": {
"indexable": true,
"rootLevel": false
}
}]
This Jolt Spec should work for you. Tested with https://jolt-demo.appspot.com/
[
{
"operation": "shift",
"spec": {
"*": {
"uuid": "[&1].uuid",
"pageId": "[&1].pageId",
"page": {
"indexable": "[&2].page.indexable",
"rootLevel": "[&2].page.rootLevel",
"homePage": "[&2].homePage"
}
}
}
}
]
input:
{
"uuid" : "cac40601-ffc9-4fd0-c5a1-772ac65f0587",
"pageId" : 123456,
"page" : {
"indexable" : true,
"rootLevel" : false
},
"homePage" : false
}
output:
[ {
"uuid" : "cac40601-ffc9-4fd0-c5a1-772ac65f0587",
"pageId" : 123456,
"page" : {
"indexable" : true,
"rootLevel" : false
},
"homePage" : false
} ]
Explanation:
From the javadoc
& Path lookup
As Shiftr processes data and walks down the spec, it maintains a data structure describing the path it has walked.
The & wildcard can access data from that path in a 0 major, upward oriented way.
Example:
{
"foo" : {
"bar": {
"baz": // &0 = baz, &1 = bar, &2 = foo
}
}
}
Next thing: How to wrap the output object into the array?
A good example can be found in this post.
So, in our case:
"[&1].uuid" says:
Place the uuid value in the object inside the array. The index of the array is indicated by the &1 wildcard. For uuid it will be the index of the array, where the object with uuid key is placed in the original json.
Next, [&2] is similar to [&1]. However, looking at the "indexable" key, it is one level deeper in the input json. Thats why instead of [&1] we used [&2] (have a look again at the foo-bar example from the docs).

JOLT - Adding fields in JSONArray based on if condition

I have a bit of a tricky question to ask, as far as I know, I haven't seen anyone with the same problem, at least not all of them at once!
I have the following test JSON to transform:
INPUT
[
{
"test_id": 1212101011,
"someDate": "2020-03-06",
"keyToCheck": "true",
"someData": "123"
},
{
"test_id": 8787909099,
"someDate": "2020-03-09",
"keyToCheck": "false",
"someData": "456"
}
]
And I am trying to get the following output.
DESIRED
[{
"test_id": 1212101011,
"someDate": "2020-03-06",
"keyToCheck": "true",
"someData": "123",
"objToAdd": {
"id": "1",
"label": "dummy1"
}
},{
"test_id": 8787909099,
"someDate": "2020-03-09",
"keyToCheck": "false",
"someData": "456",
"objToAdd": {
"id": "2",
"label": "dummy2"
}]
I already managed to propagate all the values and change the fields' names if needed, but adding a condition is just ruining everything. Also, with the current spec I have, I am not getting an array after the transform which I can already get with my former spec.
The spec I have so far is:
SPEC USED
[
{
"operation": "shift",
"spec": {
"*": {
"keyToCheck": {
"true": {
"#1": "objToAdd.id",
"#dummy1": "objToAdd.label"
},
"false": {
"#2": "objToAdd.id",
"#dummy2": "objToAdd.label"
}
}
}
}
}
]
But as said before, it is only giving me this:
RESULT SO FAR
{
"objToAdd" : {
"id" : [ "1", "2" ],
"label" : [ "dummy1", "dummy2" ]
}
}
Which seems to be a problem of indentation. Adding [&1] before the values in the condition didn't help, and when I propagate the values with "*": "[&1].&", I am losing the item generated by the if-else condition.
Is there any way to do this?
Any help would be appreciated! Thanks in advance.
Check this spec,
[
{
"operation": "shift",
"spec": {
"*": {
"test_id": "[&1].test_id",
"someDate": "[&1].someDate",
"someData": "[&1].someData",
"keyToCheck": {
"true": {
"$": "[&3].keyToCheck",
"#1": "[&3].objToAdd.id",
"#dummy1": "[&3].objToAdd.label"
},
"false": {
"$": "[&3].keyToCheck",
"#2": "[&3].objToAdd.id",
"#dummy2": "[&3].objToAdd.label"
}
}
}
}
}
]

ElasticSearch mapping for dynamic keys for indexing a map

I have a sample json which I want to index into elasticsearch.
Sample Json Indexed:
put test/names/1
{
"1" : {
"name":"abc"
},
"2" : {
"name":"def"
},
"3" : {
"name":"xyz"
}
}
where ,
index name : test,
type name : names,
id :1
Now the default mapping generated by elasticsearch is :
{
"test": {
"mappings": {
"names": {
"properties": {
"1": {
"properties": {
"name": {
"type": "string"
}
}
},
"2": {
"properties": {
"name": {
"type": "string"
}
}
},
"3": {
"properties": {
"name": {
"type": "string"
}
}
},
"metadataFieldDefinition": {
"properties": {
"name": {
"type": "string"
}
}
}
}
}
}
}
}
If the map size increases from 3 ( currently) to suppose thousand or million, then ElasticSearch will create a mapping for each which may cause a performance issue as the mapping collection will be huge .
I tried creating a mapping by setting :
"dynamic":false,
"type":object
but it was overriden by ES. since it didnt match the indexed data.
Please let me know how can I define a mapping so that ES. doesnot creates one like the above .
I think there might be a little confusion here in terms of how we index documents.
put test/names/1
{...
document
...}
This says: the following document belongs to index test and is of type name with id 1. The entire document is treated as type name. Using the PUT API as you currently are, you cannot index multiple documents at once. ES immediately interprets 1, 2, and 3 as a properties of type object, each containing a property name of type string.
Effectively, ES thinks you are trying to index ONE document, instead of three
To get many documents into index test with a type of name, you could do this, using the CURL syntax:
curl -XPUT"http://your-es-server:9200/test/names/1" -d'
{
"name": "abc"
}'
curl -XPUT"http://your-es-server:9200/test/names/2" -d'
{
"name": "ghi"
}'
curl -XPUT"http://your-es-server:9200/test/names/3" -d'
{
"name": "xyz"
}'
This will specify the document ID in the endpoint you are index to. Your mapping will then look like this:
"test": {
"mappings": {
"names": {
"properties": {
"name": {
"type": "string"
}
}
}
}
}
Final Word: Split your indexing up into discrete operations, or check out the Bulk API to see the syntax on how to POST multiple operations in a single request.

Categories

Resources