Get the value from the response based on a condition and store it to a variable - karate

I would like to get the value from the response based on a condition and store it to a variable.
In the below JSON, I would like to store the value when the name matches to something I prefer. Is there a way to achieve this using Karate API?
{
"results": [
{
"name": "Sample1",
"email": "sample1#text.com",
"id": "U-123"
},
{
"name": "Sample2",
"email": "sample2#text.com",
"id": "U-456"
},
{
"name": "Sample3",
"email": "sample3#text.com",
"id": "U-789"
}
]
}

So after reading the comment, my interpretation is to "find" the id where name is Sample2. Easy, just use a filter() operation, refer the docs: https://github.com/karatelabs/karate#jsonpath-filters
Instead of using a filter, I'm using the JS Array find() method as a very concise example below:
* def response =
"""
{ "results": [
{ "name": "Sample1", "email": "sample1#text.com", "id": "U-123" },
{ "name": "Sample2", "email": "sample2#text.com", "id": "U-456" },
{ "name": "Sample3", "email": "sample3#text.com", "id": "U-789" }
]
}
"""
* def id = response.results.find(x => x.name == 'Sample2').id
* match id == 'U-456'
Take some time to understand how it works. Talk to someone who knows JS if needed.

Related

How to use loop for response from another feature?

Іssue in the next.
I have a feature response which I check according to schema validation
{
"name": "#string",
"director_first_name": "##string",
"director_last_name": "##string",
"director_phone": "##string",
"director_email": "##string",
"language": {
"id": "#uuid",
"name": "#string",
"code": "#string? _.length == 2"
}
}
Also I have additional feature, which has list of languages
[
{
"id": "fde1312f-2ab2-4fdf-a4f3-a7095dd89a4d",
"name": "English",
"code": "EN"
},
{
"id": "0d4c6626-1010-4dda-8721-665071ec3b28",
"name": "Swedish",
"code": "SV"
}
]
And I need to check the next
Need to take response.language.id from first response and check if this id is represented in the second response. In this case I need to call this second feature.
If it is represented, need to match if id, name, code which belong to first reponse the same as in the second response.
You can do this in one line. I leave it as an exercise to you to get the data from a second feature file if you wish.
* def data =
"""
[
{
"id": "fde1312f-2ab2-4fdf-a4f3-a7095dd89a4d",
"name": "English",
"code": "EN"
},
{
"id": "0d4c6626-1010-4dda-8721-665071ec3b28",
"name": "Swedish",
"code": "SV"
}
]
"""
* def response =
"""
{
"language": {
"id": "fde1312f-2ab2-4fdf-a4f3-a7095dd89a4d",
"name": "English",
"code": "EN"
}
}
"""
* match response.language == data.find(x => x.code == response.language.code)
Take some time to read other answers (and follow the links) for ideas: https://stackoverflow.com/a/70055035/143475

Karate: How to remove dynamic element based on value from JSON?

I have a requirement, in the below JSON I have to delete all the id elements,
[
{
"id": "0a7936ed",
"code": "test",
"label": "test",
"type": "sell"
},
{
"id": "7bc1909b2",
"code": "test2",
"label": "test2",
"type": "Buy"
}
]
My JSON should be as below,
[
{
"code": "test",
"label": "test",
"type": "sell"
},
{
"code": "test2",
"label": "test2",
"type": "Buy"
}
]
Standard JS Array operations will work in Karate 1.0 onwards:
* def dest = source.map(x => { delete x.id; return x })
For older versions of Karate, a hint is that you can loop over any JS object key-values using karate.forEach() and you could write conditional logic to ignore id etc.

Apache Nifi: UpdateRecord replace child values

I'm trying to use UpdateRecord 1.9.0 processor to modify a JSON but it does not replace the values as I want.
this is the source message
{
"type": "A",
"ids": [{
"id": "1",
"value": "abc"
}, {
"id": "2",
"value": "def"
}, {
"id": "3",
"value": "ghi"
}
]
}
and the wanted output
{
"ids": [{
"userId": "1",
}, {
"userId": "2",
}, {
"userId": "3",
}
]
}
I have configured the processor as follows
processor config
Reader:
reader
Schema registry:
schema
writer:
writer
And it works, the output is a JSON without the field 'type' and the ids have the field 'userId' instead 'id' and 'value'.
To fill the value of userId, I defined the replace strategy and the property to replace:
strategy
But the output is wrong. The userId is always filled with the id of the last element in the array:
{
"ids": [{
"userId": "3"
}, {
"userId": "3"
}, {
"userId": "3"
}
]
}
I think the value of the expression is ok because if I try to replace only one record it works fine (/ids[0]/userId, ..id)
Nifi docs has a really similar example (example 3):
https://nifi.apache.org/docs/nifi-docs/components/org.apache.nifi/nifi-standard-nar/1.7.1/org.apache.nifi.processors.standard.UpdateRecord/additionalDetails.html
But it does not work for me.
What am I doing wrong?
thanks
Finally I have used JoltJSONTransform processor instead UpdateRecord
JoltJSONTransform
template:
[
{
"operation": "shift",
"spec": {
"ids":{
"*":{
"id": "ids[&1].userId"
}
}
}
}
]
Easier than UpdateRecord

Transform JSON response with lodash

I'm new in lodash (v3.10.1), and having a hard time understanding.
Hope someone can help.
I have an input something like this:
{
{"id":1,"name":"Matthew","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":2,"name":"Mark","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":3,"name":"Luke","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":4,"name":"John","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":5,"name":"Paul","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}}
];
I would like to output this or close to this:
{
"industries": [
{
"industry":{
"id":5,
"name":"Medical",
"companies": [
{
"company":{
"id":1,
"name":"abc",
"employees": [
{"id":1,"name":"Matthew"},
{"id":2,"name":"Mark"},
{"id":3,"name":"Luke"},
{"id":4,"name":"John"},
{"id":5,"name":"Paul"}
]
}
}
]
}
}
]
}
Here's something that gets you close to what you want. I structured the output to be an object instead of an array. You don't need the industries or industry properties in your example output. The output structure looks like this:
{
"industry name": {
"id": "id of industry",
"companies": [
{
"company name": "name of company",
"id": "id of company",
"employees": [
{
"id": "id of company",
"name": "name of employee"
}
]
}
]
}
}
I use the _.chain function to wrap the collection with a lodash wrapper object. This enables me to explicitly chain lodash functions.
From there, I use the _.groupBy function to group elements of the collection by their industry name. Since I'm chaining, I don't have to pass in the array again to the function. It's implicitly passed via the lodash wrapper. The second argument of the _.groupBy is the path to the value I want to group elements by. In this case, it's the path to the industry name: company.industry.name. _.groupBy returns an object with each employee grouped by their industry (industries are keys for this object).
I then do use _.transform to transform each industry object. _.transform is essentially _.reduce except that the results returned from the _.transform function is always an object.
The function passed to the _.transform function gets executed against each key/value pair in the object. In the function, I use _.groupBy again to group employees by company. Based off the results of _.groupBy, I map the values to the final structure I want for each employee object.
I then call the _.value function because I want to unwrap the output collection from the lodash wrapper object.
I hope this made sense. If it doesn't, I highly recommend reading Lo-Dash Essentials. After reading the book, I finally got why lodash is so useful.
"use strict";
var _ = require('lodash');
var emps = [
{ "id": 1, "name": "Matthew", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 2, "name": "Mark", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 3, "name": "Luke", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 4, "name": "John", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 5, "name": "Paul", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } }
];
var result = _.chain(emps)
.groupBy("company.industry.name")
.transform(function(result, employees, industry) {
result[industry] = {};
result[industry].id = _.get(employees[0], "company.industry.id");
result[ industry ][ 'companies' ] = _.map(_.groupBy(employees, "company.name"), function( employees, company ) {
return {
company: company,
id: _.get(employees[ 0 ], 'company.id'),
employees: _.map(employees, _.partialRight(_.pick, [ 'id', 'name' ]))
};
});
return result;
})
.value();
Results from your example are as follows:
{
"Medical": {
"id": 5,
"companies": [
{
"company": "abc",
"id": 1,
"employees": [
{
"id": 1,
"name": "Matthew"
},
{
"id": 2,
"name": "Mark"
},
{
"id": 3,
"name": "Luke"
},
{
"id": 4,
"name": "John"
},
{
"id": 5,
"name": "Paul"
}
]
}
]
}
}
If you ever wanted the exact same structure as in the questions, I solved it using the jsonata library:
(
/* lets flatten it out for ease of accessing the properties*/
$step1 := $ ~> | $ |
{
"employee_id": id,
"employee_name": name,
"company_id": company.id,
"company_name": company.name,
"industry_id": company.industry.id,
"industry_name": company.industry.name
},
["company", "id", "name"] |;
/* now the magic begins*/
$step2 := {
"industries":
[($step1{
"industry" & $string(industry_id): ${
"id": $distinct(industry_id)#$I,
"name": $distinct(industry_name),
"companies": [({
"company" & $string(company_id): {
"id": $distinct(company_id),
"name": $distinct(company_name),
"employees": [$.{
"id": $distinct(employee_id),
"name": $distinct(employee_name)
}]
}
} ~> $each(function($v){ {"company": $v} }))]
}
} ~> $each(function($v){ {"industry": $v} }))]
};
)
You can see it in action on the live demo site: https://try.jsonata.org/VvW4uTRz_

How to invert the MQL query (for freebase)?

I am trying to list all the types for a particular id:
{
"id": "/en/sony",
"type": [{
"name": "Topic",
"id": null
}]
}
This query giving me the following result:
http://tinyurl.com/lubavey
{
"result": {
"type": [
{
"id": "/common/topic",
"name": "Topic"
},
{
"id": "/base/audiobase/topic",
"name": "Topic"
},
{
"id": "/base/fblinux/topic",
"name": "Topic"
},
{
"id": "/base/digitalcameras/topic",
"name": "Topic"
},
{
"id": "/base/popstra/topic",
"name": "Topic"
},
{
"id": "/base/televisions/topic",
"name": "Topic"
},
{
"id": "/base/ps3games/topic",
"name": "Topic"
},
{
"id": "/base/filmcameras/topic",
"name": "Topic"
},
{
"id": "/m/04mny2g",
"name": "Topic"
}
],
"id": "/en/sony"
}
}
I want exactly the opposite result. I want all the types which do not have name as "Topic" with them.
How can I achieve this? I tried to use ! operator with property name which is suggested in reference guide of MQL, but it's giving me error:
"Can't use unqualified property names with ! reversing".
What should I do to remove this error with ! and to obtain opposite result of the query?
Try with !=:
{
"id": "/en/sony",
"type": [{
"name!=": "Topic",
"id": null
}]
}
The != operator says that the constrained property can be anything but
the specified value. (It does require that the property be something,
however: it does not match object for which the property is null.)
Read more about != operator here: http://wiki.freebase.com/wiki/MQL_operators#The_.22but_not.22_Operator_.21.3D