RestAssured JsonPath: flat array of elements in hierarchy - java

I'm writing a smoke test using rest-assured and want to traverse the api to make sure no unexpected errors occur.
I have a data structure that looks like this:
{
...
"sites": [
{
...
"groups": [
{
...
"locations": [
{
...
"racks": [
{
"rackId": 123456789,
...
},
{
"rackId": 987654321,
...
},
...
]
}
]
}
]
},
{
...
"groups": [
{
...
"locations": [
{
...
"racks": [
{
"rackId": 11111111,
...
},
{
"rackId": 22222222,
...
},
...
]
}
]
}
]
},
...
]
}
Using JsonPath bundled in RestAssured I'm trying to get a flat list of all rackIds to then call subsequent requests for these rackIds.
jsonPath.getList("sites.groups.locations.racks.rackId", Long.class);
>> java.lang.NumberFormatException: For input string: "[[[406071537, 406071538, 406071539, 406071540, 406071541]]]"
I tried using this path, but didn't work because I believe this syntax only works with the other JsonPath implementation, not the one bundled with rest-assured
"$.sites[*].groups[*].locations[*].racks[*].rackId"
I now came down to this, that gives me lists of lists of lists, that I could then flatten myself. But I then have the issue, that the numbers interpreted as Integers by default, but I'm receiving Long values.
List list = jsonPath.getList("sites.groups.locations.racks.rackId");
Any ideas?

Just use flatten():
List list = jsonPath.getList("sites.groups.locations.racks.rackId.flatten()");

Related

mongoDB query document with multiple layer of nested array

{
"sections": [
{
"desc": "no flow ID",
"sectionObj": [
{
"smartFlowIdList": []
}
]
},
{
"desc": "has flow ID",
"sectionObj": [
{
"smartFlowIdList": [
"smartFlowId1",
"smartFlowId2"
]
}
]
]
}
// Query document to see if any of the sections[].sectionObj[].smartFlowIdList has at least a flowId1
// in this case: it is True since [ "smartFlowId1", "smartFlowId2" ] exits
I need to query this document with MongoDB shell commands.
I have tried looking at $[], $all and digging up on mongo documentation but can seem to get anywhere. Any idea is appreciated, thanks!
One option is to iterate twice, per each nested level and count the items in last nested level. $match documents with count greater than 0:
db.collection.aggregate([
{$match: {$expr:
{$gt: [
{$sum: {$map: {
input: "$sections",
as: "external",
in: {$sum: [
{$reduce: {
input: "$$external.sectionObj",
initialValue: 0,
in: {$sum: ["$$value", {$size: "$$this.smartFlowIdList"}]}
}
}
]
}
}}},
0
]}
}}
])
See how it works on the playground example

Use JsonPath to read nested array properties

[
{
"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.

JSONPath and Traverson filtering: single element array

Here is the Json I am trying to handle with Traverson to extract a single link from this HAL:
{
"_links": {
"curies": [
{
"href": "https://localhost/auth/def/rels/{rel}",
"name": "auth",
"templated": true
}
],
"self": {
"href": "https://localhost/auth/identity"
}
},
"_embedded": {
"auth": [
{
"_links": {
"auth:ad": [
{
"href": "https://localhost/auth/ad"
}
]
},
"kind": "oauth2"
},
{
"_links": {
"auth:default": [
{
"href": "https://localhost/auth/default" // **Link that I need**
}
]
},
"kind": "oauth2"
}
]
}
}
Java code responsible for handling ideally should look like this:
Link test = traverson
.follow("auth")
.follow("$.['_embedded']['auth']..['_links']['auth:default']..['href'][0]")
.asLink();
But for some reason I am getting no hits despite the fact that right before adding the last [0] in the JSONPath expression I am getting an array of one element. Is there a way to extract this single link so that I am not returned with an array? I used this tool for testing.
The code necessary to achieve what I should look like this:
JsonPathLinkDiscoverer disc = new JsonPathLinkDiscoverer("$._embedded..auth.._links..['%s']..href", MediaTypes.HAL_JSON);
Link authLink = disc.findLinksWithRel("auth:default", <json>).get(0);
where <json> should be the json representation of the example in the original question (probably like a reponse from other call).

rest assured to match value from a root json array

Am new to rest assured
I have a json response like this
{
"queryPath": "/api/",
"nId": "f084f5ad24fcfaa9e9faea0",
"statusCode": 707
"statusMessage": "Success",
"results": {
"data": [
{
"id": "10248522500798",
"capabilities": [
"men",
"women"
],
"name": "errt2"
},
{
"id": "418143778",
"capabilities": [
"dog",
"cat"
],
"name": "Livin"
}
]
}
}
String type = "men"
Using rest assured i need to check the type value men with capabilities array values
[
"men",
"women"
]
and
"capabilities": [
"dog",
"cat"
]
If the type value `men` not contains in any of the capabilities i need to raise error..how it is possible?
i used following code .But it is not working.any other way??
body("results.data.capabilities", hasItems(type));
Am getting error
Expected: (a collection containing "men")
Actual: [[ men,women
], [dog, cat]]
The problem is that your jsonPath
results.data.capabilities
points to both "capabilities" arrays since they are nested at the same level of your JSON. If you can reliably expect the first "capabilities" array to contain "men" then you can specify the first "capabilities" in your jsonPath like so:
results.data.capabilities[0]

neo4j - how to run queries with 1000 objects via rest api

I'm need run queries with 1000 objects. Using /batch endpoint I can get this to work but is too slow (30 seconds with 300 items).
So I'm trying the same approach as said in this docs page: http://docs.neo4j.org/chunked/2.0.1/rest-api-cypher.html#rest-api-create-mutiple-nodes-with-properties
POST this JSON to http://localhost:7474/db/data/cypher
{
"params": {
"props": [
{
"_user_id": "177032492760",
"_user_name": "John"
},
{
"_user_id": "177032492760",
"_user_name": "Mike"
},
{
"_user_id": "100007496328",
"_user_name": "Wilber"
}
]
},
"query": "MERGE (user:People {id:{_user_id}}) SET user.id = {_user_id}, user.name = {_user_name} "
}
The problem is I'm getting this error:
{ message: 'Expected a parameter named _user_id',
exception: 'ParameterNotFoundException',
fullname: 'org.neo4j.cypher.ParameterNotFoundException',
stacktrace:
...
Maybe this works only with CREATE queries, as showing in the docs page?
Use FOREACH and MERGE with ON CREATE SET:
FOREACH (p in {props} |
MERGE (user:People {id:{p._user_id}})
ON CREATE user.name = {p._user_name})
POST this JSON to http://localhost:7474/db/data/cypher
{
"params": {
"props": [
{
"_user_id": "177032492760",
"_user_name": "John"
},
{
"_user_id": "177032492760",
"_user_name": "Mike"
},
{
"_user_id": "100007496328",
"_user_name": "Wilber"
}
]
},
"query": "FOREACH (p in {props} | MERGE (user:People {id:{p._user_id}}) ON CREATE user.name = {p._user_name}) "
}
Actually, the equivalent to the example in the doc would be:
{
"params": {
"props": [
{
"id": "177032492760",
"name": "John"
},
{
"id": "177032492760",
"name": "Mike"
},
{
"id": "100007496328",
"name": "Wilber"
}
]
},
"query": "CREATE (user:People {props})"
}
It might be legal to replace CREATE to MERGE, but the query may not do what you expect.
For example, if a node with the id "177032492760" already exists, but it does not have the name "John", then the MERGE will create a new node; and you'd end up with 2 nodes with the same id (but different names).
Yes, a CREATE statement can take an array of maps and implicitly convert it to several statements with one map each, but you can't use arrays of maps that way outside of simple create statements. In fact you can't use literal maps the same way either when you use MERGE and MATCH. You can CREATE ({map}) but you have to MATCH/MERGE ({prop:{map}.val} i.e.
// {props:{name:Fred, age:2}}
MERGE (a {name:{props}.name})
ON CREATE SET a = {props}
For your purposes either send individual parameter maps with a query like above or for an array of maps iterate through it with FOREACH
FOREACH (p IN props |
MERGE (user:People {id:p._user_id})
ON CREATE SET user = p)

Categories

Resources