Extracting and processing from JSON response - jmeter

I am doing a hotel search by entering the hotel names.Below is the valid JSON response. This is a response for one hotel search. I have run 15 threads and I have 14 more JSON response for different hotels similar to this one. In this response you can see "providers" and "results" that refer to the providers with array values. My requirement is to find out how many offers ie., results each provider has in total across all the 15 hotels.
"providers":
[
{
"MM_logofile":"agd.svg",
"MM_isOfficialWithoutLogo":false,
"code":"AGD",
"name":"Agoda.com",
"logo":"AGD.png",
"isOfficial":false
},
{
"MM_logofile":"ian.svg",
"MM_isOfficialWithoutLogo":false,
"code":"IAN",
"name":"Hotels.com",
"logo":"IAN-Other.png",
"isOfficial":false
},
{
"MM_logofile":"gar.svg",
"MM_isOfficialWithoutLogo":false,
"code":"GAR",
"name":"getaroom.com",
"logo":"GAR.png",
"isOfficial":false
},
{
"MM_logofile":"exp.svg",
"MM_isOfficialWithoutLogo":false,
"code":"EXP",
"name":"Expedia.dk",
"logo":"EXP-DK.png",
"isOfficial":false
},
{
"MM_logofile":"acc.svg",
"MM_isOfficialWithoutLogo":false,
"code":"ACC",
"name":"AccorHotels.com",
"logo":"ACC.png",
"isOfficial":true
},
],
"results":
[
{
"roomName":"Standard Twin Rm Special Offer - Best price guarantee",
"totalRate":918.0,
"isCheapestRate":true,
"hasFreeCancelation":false,
"inclusions":
[
],
"availableRooms":null,
"providerIndex":0,
"includesAllTaxes":false,
"excludedCharges":
[
0
],
"bookUri":"https://72750.api.hotelscombined.com/ProviderRedirect.ashx?key=0.11648360.-378376995.495.USD.123155627&source=202-0&a_aid=72750&brandID=177977"
},
{
"roomName":"Standard Double Rm Special Offer - Best price guarantee",
"totalRate":918.0,
"isCheapestRate":false,
"hasFreeCancelation":false,
"inclusions":
[
],
"availableRooms":null,
"providerIndex":0,
"includesAllTaxes":false,
"excludedCharges":
[
0
],
"bookUri":"https://72750.api.hotelscombined.com/ProviderRedirect.ashx?key=0.11648360.-378376995.496.USD.1523114518&source=202-1&a_aid=72750&brandID=177977"
},
{
"roomName":"Standard Double Room Hot Deal - Best price guarantee",
"totalRate":918.0,
"isCheapestRate":false,
"hasFreeCancelation":false,
"inclusions":
[
],
"availableRooms":null,
"providerIndex":1,
"includesAllTaxes":false,
"excludedCharges":
[
0
],
"bookUri":"https://72750.api.hotelscombined.com/ProviderRedirect.ashx?key=0.11648360.-378376995.497.USD.573302441&source=202-2&a_aid=72750&brandID=177977"
},
{
"roomName":"Standard Twin Room Hot Deal - Best price guarantee",
"totalRate":918.0,
"isCheapestRate":false,
"hasFreeCancelation":false,
"inclusions":
[
],
"availableRooms":null,
"providerIndex":2,
"includesAllTaxes":false,
"excludedCharges":
[
0
],
"bookUri":"https://72750.api.hotelscombined.com/ProviderRedirect.ashx?key=0.11648360.-378376995.498.USD.1523907592&source=202-3&a_aid=72750&brandID=177977"
},
{
"roomName":"Standard Room, 1 Double Bed",
"totalRate":926.2,
"isCheapestRate":false,
"hasFreeCancelation":false,
"inclusions":
[
],
"availableRooms":null,
"providerIndex":3,
"includesAllTaxes":false,
"excludedCharges":
[
0
],
"bookUri":"https://72750.api.hotelscombined.com/ProviderRedirect.ashx?key=0.13476094.-378377052.1210.USD.1325439035&source=202-4&a_aid=72750&brandID=177977"
},
],

Following is the beanshell code:
import java.util.HashMap;
import java.util.Map;
results_count = Integer.parseInt(vars.get("results_matchNr"));
providers_count = Integer.parseInt(vars.get("providers_matchNr"));
log.info("total results " + results_count);
Map results = new HashMap();
Map providers = new HashMap();
for(i=1; i<=providers_count; i++){
log.info("iteration " + i);
temp = vars.get("providers_"+i);
log.info("provider_name " + temp);
providers.put(i-1, temp);
}
log.info("providers: " + providers);
int provider_index = -1;
String provider_name = "";
for(i=1; i<=results_count; i++){
log.info("iteration " + i);
provider_index = Integer.parseInt(vars.get("results_"+i));
log.info("provider_index " + provider_index);
provider_name = providers.get(provider_index);
log.info("provider name :" + provider_name);
if(results.get(provider_name) == null){
log.info("ading key for the first time " + provider_name);
results.put(provider_name, 1);
}
else{
log.info("second time " + provider_name);
int existing = results.get(provider_name);
log.info("exisiting value " + existing);
int updateValue = existing+1;
log.info("updated value: " + updateValue);
results.put(provider_name, updateValue);
}
}
log.info("results-providers mapping " + results);
int threadNum = ctx.getThreadNum();
// if you want to log something to jmeter.log file
// Pass true if you want to append to existing file othewise false.
f = new FileOutputStream("G:\\naveen\\mywork\\testing\\performance\\tools\\jmeter\\examples\\result.csv", true);
p = new PrintStream(f);
this.interpreter.setOut(p);
String output = "thread number#" + threadNum + " " + results;
print(output);
f.close();
Add BeanShell PostProcessor to the sampler and add the above code.
Add JSONPATH Extractor to get the providers and add the following syntax:
$.providers[*].name
Add another JSONPATH Extractor to get the results/offers and add the following syntax:
$.results[*].providerIndex
Note: change the file location to store the results as per your machine in the beanshell code.
Following is the results which will be saved into the file:
thread number#0 {Expedia.dk=1, Agoda.com=2, Hotels.com=1, getaroom.com=1}
thread number#1 {Expedia.dk=1, Agoda.com=2, Hotels.com=1, getaroom.com=1}
// two rows for two threads. here, Agoda.com provider has two offers, so the count is 2 and remaining providers has one offer each.
Note: verified the script for 2 users. there will be two entries present in the results file (one thread -> one row). chnage the foramt as per your requirements on beanshell code (code related to file writing).

Related

elasticsearch sort by price with currency

I have data
{
"id": 1000,
"price": "99,01USA",
},
{
"id": 1001,
"price": "100USA",
},
{
"id": 1002,
"price": "780USA",
},
{
"id": 1003,
"price": "20USA",
},
How I sort order by price (ASC , DESC)
You can alter it a little to parse price to integer and then sort it
You can create a dynamic sort function that sorts objects by their value that you pass:
function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
/* next line works with strings and numbers,
* and you may want to customize it to your needs
*/
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
So you can have an array of objects like this:
var People = [
{Name: "Name", Surname: "Surname"},
{Name:"AAA", Surname:"ZZZ"},
{Name: "Name", Surname: "AAA"}
];
...and it will work when you do:
People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));
Actually this already answers the question. Below part is written because many people contacted me, complaining that it doesn't work with multiple parameters.
Multiple Parameters
You can use the function below to generate sort functions with multiple sort parameters.
function dynamicSortMultiple() {
/*
* save the arguments object as it will be overwritten
* note that arguments object is an array-like object
* consisting of the names of the properties to sort by
*/
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
/* try getting a different result from 0 (equal)
* as long as we have extra properties to compare
*/
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}
Which would enable you to do something like this:
People.sort(dynamicSortMultiple("Name", "-Surname"));
Subclassing Array
For the lucky among us who can use ES6, which allows extending the native objects:
class MyArray extends Array {
sortBy(...args) {
return this.sort(dynamicSortMultiple(...args));
}
}
That would enable this:
MyArray.from(People).sortBy("Name", "-Surname");

Terraform output object with multiple attributes for each of `for` resources?

I have terraform with a resource being created with for. As is typical, each instance of this resource has several attributes. At the moment I have a series of map outputs for this resource group but each consists of only a single key-value pair. I would like my terraform output to include a list or map of maps or objects with all of the attributes grouped by resource instance. How do I do this without using flatten; zipmap etc to construct them from my current outputs? This example is with aws_route53_record but this is a generic query:
Current code
output "r53record_zonal_fqdn" {
value = {
for entry in aws_route53_record.zonal :
entry.name => entry.fqdn
}
}
output "r53record_zonal_records" {
value = {
for entry in aws_route53_record.zonal :
entry.name => entry.records
}
}
output "r53record_zonal_zone_id" {
value = {
for entry in aws_route53_record.zonal :
entry.name => entry.zone_id
}
}
As you would expect, this renders three maps with aws_route53_record.zonal.name as the key and the other attribute(s) as the value.
What I would like is to have these outputs grouped by resource with a predefined key for each value, e.g. (pseudocode):
output "r53record_zonal_zone_id" {
value = {
for entry in aws_route53_record.zonal : {
instance[count.index] {
"name" = entry.name
"fqdn" = entry.fqdn
"records" = entry.records
"zone_id" = entry.zone_id
}
}
}
}
Producing a map or list of maps for each instance.
How can this or something like it be done?
I created a random route53_record resource block with two "name" arguments in for_each loop and tried to output something close to what you were looking for.
Assuming "mydomain.com" is the domain in Route53 as example....
resource "aws_route53_record" "zonal" {
for_each=toset(["site1","site2"])
name = each.key
zone_id = "ABCDZONEIDSTRING"
type = "A"
ttl = "300"
records = ["192.168.1.10"]
}
output "test" {
value = {
for dns, details in aws_route53_record.zonal:
dns => ({"fqdn" = details.fqdn , "zone_id" = details.zone_id , "records" = details.records})
}
}
this will create output in this fashion..
test = {
"site1" = {
"fqdn" = "site1.mydomain.com"
"records" = [
"192.168.1.10",
]
"zone_id" = "Z0630117NTQNSYTXYQ4Z"
}
"site2" = {
"fqdn" = "site2.mydomain.com"
"records" = [
"192.168.1.10",
]
"zone_id" = "Z0630117NTQNSYTXYQ4Z"
}
}
Suppose you passed the name values with domain name, like below...
for_each=toset(["site1.mydomain.com","site2.mydomain.com"])
the output would look like
test = {
"site1.mydomain.com" = {
"fqdn" = "site1.mydomain.com"
"records" = [
"192.168.1.10",
]
"zone_id" = "ABCDMYZONEIDSTRING"
}
"site2.mydomain.com" = {
"fqdn" = "site2.mydomain.com"
"records" = [
"192.168.1.10",
]
"zone_id" = "ABCDMYZONEIDSTRING"
}
}

Group By (Aggregation) to get only latest fields value

I write a query to read the metricbeat file. This gives me the whatever I want but it repeats the value multiple time.
I want to group by this on latest timestamp so I can get only latest record.
Below is my query
string indexName = "metricbeat-7.4.2-" + DateTime.Now.Year.ToString() + "." + DateTime.Now.Month.ToString("00") + "." + DateTime.Now.Day.ToString("00");
connectionSettings = new ConnectionSettings(connectionPool).DefaultIndex(indexName);
elasticClient = new ElasticClient(connectionSettings);
string[] systemFields = new string[]
{
"system.memory.actual.used.pct",
"system.cpu.total.norm.pct"
};
var elasticResponse = elasticClient.Search<object>(s => s
.DocValueFields(dvf => dvf.Fields(systemFields))
);
DSL query
get /metricbeat*/_search?pretty=true
{
"query" : {
"match_all": {}
},
"docvalue_fields" : [
"system.memory.actual.used.pct",
"system.cpu.total.norm.pct",
"system.load.5",
"docker.diskio.summary.bytes"
]
}

Merge fails in terraform

Consider I have a variable -
[
{
"outer_key_1" = [
{
"ip_cidr" = "172.16.6.0/24"
"range_name" = "range1"
},
{
"ip_cidr" = "172.16.7.0/24"
"range_name" = "range2"
},
{
"ip_cidr" = "172.17.6.0/24"
"range_name" = "range3"
},
{
"ip_cidr" = "172.17.7.0/24"
"range_name" = "range4"
},
]
},
{
"outer_key_2" = [
{
"ip_cidr" = "172.16.5.0/24"
"range_name" = "range5"
},
{
"ip_cidr" = "172.17.5.0/24"
"range_name" = "range6"
},
]
},
]
I am able to merge the maps inside the list to get this output -
{
"outer_key_1" = [
{
"ip_cidr" = "172.16.6.0/24"
"range_name" = "range1"
},
{
"ip_cidr" = "172.16.7.0/24"
"range_name" = "range2"
},
{
"ip_cidr" = "172.17.6.0/24"
"range_name" = "range3"
},
{
"ip_cidr" = "172.17.7.0/24"
"range_name" = "range4"
},
]
"outer_key_2" = [
{
"ip_cidr" = "172.16.5.0/24"
"range_name" = "range5"
},
{
"ip_cidr" = "172.17.5.0/24"
"range_name" = "range6"
},
]
}
I have done this using
result = merge(variable[0], variable[1])
But when I try this
result = merge(variable[*])
I get an error saying
Call to function "merge" failed: arguments must be maps or objects, got
"tuple".
Why does merge fail when I use the splat operator?
Is there a better way to merge maps in list as required above?
The merge function is defined to take one or more separate arguments that are each map or object values. When you call merge(variable) (which is the same as merge(variable[*]) if variable is already a list) you're instead giving it one list argument, leading to this error.
To pass the elements of a list or tuple as multiple individual arguments, you can use argument expansion syntax:
result = merge(variable...)
The ... symbol, when given after the last argument in a function call, tells Terraform to evaluate the expression as a list or tuple before calling the function, and then use the elements in that result a separate argument each.
In other words, merge(variable...) is the same as merge(variable[0], variable[1], variable[2]) etc for each element in the list, without needing to know ahead of time how many elements are in the list.
Applying the splat operator [*] to a value that is already a list is redundant; the splat operator is useful in this situation only when it's followed by at least one additional attribute name or index, like example[*].id or example[*][0].
There is one situation where a lonely [*] with no following steps can be useful: if you apply it to anything that isn't a list or tuple then Terraform will either wrap it in a single-element list (if it's non-null) or return an empty list (if it's null), which can be useful in some unusual cases where you're given a single value that might be null and need to adapt it into a zero-or-one length list to use with features like resource for_each and in dynamic blocks.

MongoDB multikey index write performance degrading

In MongoDB I have a collection with documents having an array with subdocuments I would like to have an index on:
{
_id : ObjectId(),
members : [
{ ref : ObjectId().str, ... },
{ ref : ObjectId().str, ... },
...
]
}
The index is on the ref field, such that I can quickly find all documents having a particular 'ref' in its members:
db.test.ensureIndex({ "members.ref" : 1 });
I noticed that the performance of pushing an additional subdocument to the array degrades fast as the array length goes above a few thousand. If I instead use an index on an array of strings, the performance does not degrade.
The following code demonstrates the behavior:
var _id = ObjectId("522082310521b655d65eda0f");
function initialize () {
db.test.drop();
db.test.insert({ _id : _id, members : [], memberRefs : [] });
}
function pushToArrays (n) {
var total, err, ref;
total = Date.now();
for (var i = 0; i < n; i++) {
ref = ObjectId().str;
db.test.update({ _id : _id }, { $push : { members : { ref : ref }, memberRefs : ref } });
err = db.getLastError();
if (err) {
throw err;
}
if ((i + 1) % 1000 === 0) {
print("pushed " + (i + 1));
}
}
total = Date.now() - total;
print("pushed " + n + " in " + total + "ms");
}
initialize();
pushToArrays(5000);
db.test.ensureIndex({ "members.ref" : 1 });
pushToArrays(10);
db.test.dropIndexes();
db.test.ensureIndex({ "memberRefs" : 1 });
pushToArrays(10);
db.test.dropIndexes();
E.g., using MongoDB 2.4.6 on my machine I see the following times used to push 10 elements on arrays of length 5000:
Index on "members.ref": 37272ms
Index on "memberRefs": 405ms
That difference seems unexpected. Is this a problem with MongoDB or my use of the multikey index? Is there a recommended way of handling this? Thanks.
Take a look at SERVER-8192 and SERVER-8193. Hopefully that will help answer your question!

Resources