Way to get index of current element in ARRAY expression? - couchbase

The ARRAY expression works similar to the Array.prototype.map method in JS in that it translates elements from one array to a new array. One thing missing from ARRAY is the ability to get the index of the current element.
For example, is there a way to do this succinctly with ARRAY in n1ql?
// returns [{x: 7, i: 0}, {x: 3, i: 1}]
[{x: 7}, {x: 3}].map((obj, i) => ({...obj, i}));
Something like this would be a nice API:
SELECT ARRAY OBJECT_PUT(obj, "i", i) FOR obj, i IN [{x: 7}, {x: 3}] END
where you can define two variables after FOR: the first being the current array element and the optional second variable being the current array index.
Is there a valid way to do this easily?

You can use ARRAY_POSITION() function to get the index. https://developer.couchbase.com/documentation/server/4.6/n1ql/n1ql-language-reference/arrayfun.html#story-h2-15
And, yes multiple FOR expressions can be used in the ARRAY construct, which can be iterated together (i.e they should be of same size).
https://developer.couchbase.com/documentation/server/4.6/n1ql/n1ql-language-reference/collectionops.html
For ex:
SELECT ARRAY {i, j} FOR i IN [10, 11, 12], j IN [0, 1, 2] END;
[
{
"$1": [
{
"i": 10,
"j": 0
},
{
"i": 11,
"j": 1
},
{
"i": 12,
"j": 2
}
]
}
]

SELECT ARRAY {"x":v.x, "i": ARRAY_POS([{"x": 7}, {"x": 3}],v)} FOR v IN [{"x": 7}, {"x": 3}] END;

Related

I want to return object with timestramp and count

I have list which contains multiple similar timestamps i have count their occurrences like below code :
count = collections.Counter(MyList)
return [{"result": count}]
It gives me result like this :
"2021-10-09T00:26:16": 10,
"2021-10-08T15:08:37": 5,
"2021-10-08T13:40:50": 6,
But I want a result like this
{"timestamp": "2021-01-01T00:00:00", "count": 10},
{"timestamp": "2021-01-02T00:00:00", "count": 5},
{"timestamp": "2021-01-03T00:00:00", "count": 6},
You can use Dictionary Comprehension to meet the requirement.
count = collections.Counter(MyList)
result = [{'timestamp': k, 'count': v} for k,v in count.items()]
Learn more about Dictionary Comprehension from PEP 274 -- Dict Comprehensions.

Reshape a jq array with summarized data

New to jq but I've managed to group a load of data which I would now like summarized in a different format. Original data after group by and mapping:
[
{
"Agents": "a",
"Count": 1
},
{
"Agents": "b",
"Count": 50
},
{
"Agents": "c",
"Count": 25
},
{
"Agents": "d",
"Count": 1
},
{
"Agents": "e",
"Count": 4
},
{
"Agents": "f",
"Count": 4
},
{
"Agents": "g",
"Count": 4
}
]
and I would like this output:
{
"Count": 7,
"Agents": {
"a": 1,
"b": 50,
"c": 25,
"d": 1,
"e": 4,
"f": 4,
"g": 4
}
}
How exactly might I do this in jq please because it requires mapping the values as field names?
Another variant using reduce would be to do. The reduce expression takes the array as input and puts the key as the Agents and the value as its corresponding Count value.
jq '{ Count: length, Agents: (reduce .[] as $d ({}; .[$d.Agents] = $d.Count)) }'
The Object Value Iterator .[] used to construct the JSON. For a given .["a"], it returns "a" which is how the keys are constructed in the final JSON.
Use map to create an input for from_entries:
map({key: .Agents, value: .Count}) | {Count: length, Agents: from_entries}
map produces a list of objects like [{"key": "a", "value": 1}, ...]. from_entries turns that into a single object {"a": 1, ...}. In the final object, both length and from_entries get the same array as input, and their outputs are used to create the final object with Count and Agents keys.

Combine two objects using JsonPath

Suppose I have json like this:
[
{
"a": 1,
"b": 2,
"c": 3,
},
{
"a": 1,
"b": 2,
"d": 4
}
]
Is it possible to write a JsonPath which will give me:
{
"a": 1,
"b": 2,
"c": 3,
"d": 4
}
The order of the elements in the list is not sure, however the element names I know beforehand. So I thought I could use JsonPath to select all elements with names 'a', 'b', 'c' or 'd' and put them in a single object. However, I now have tried several things and I start to doubt whether what I want is possible.
For example I can select an object which has an element c with:
$[?(#.c)]
And I can also select just the value of d with something like:
$..d
But I can not find any way to comebine them into a single object. Is what I want possible with JsonPath or is this a limitation of JsonPath?
I think the appropriate way to do this is to remove the second object and apply the difference between them to the first one:
[
{ "op": "remove", "path": "/1" },
{ "op": "add", "path": "/0/d", "value": 4 }
]
Assuming you're OK with polyfilling for IE (it's ES6), use Object.assign:
const object1 = {
a: 1,
b: 2,
c: 3
};
const object2 = {
d: 4
}
const objectMerged = Object.assign({}, object1, object2);
console.log(objectMerged.c);
console.log(objectMerged.d);
For full details, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Browser_compatibility

Matching arrays in soapUI JSONPath RegEx Match assertions

I'm trying to make a JSONPath RegEx Match on SoapUI for the following Json Response:
{
"quantidadeItens": 5,
"registros": [
{
"identificador": 1,
"descricao": "Viagem à Disney"
},
{
"identificador": 2,
"descricao": "Carro"
},
{
"identificador": 3,
"descricao": "Smartphone novo"
},
{
"identificador": 4,
"descricao": "Casa nova"
},
{
"identificador": 5,
"descricao": "Apartamento Novo"
}
]
}
On the attached Image we can see that the JsonPath is correct, but the SoapUI is not finding the match.
I guess that the [*] is not supported on SoapUI, but I didn't find anything about it on documentation.
The expected output of your JSONPath expression would be something like:
[
1,
2,
3,
4,
5
]
This doesn't match your regex, but in any case soapUI produces [1, 2, 3, 4, 5], which the soapUI documentation says is not a JSON array but just a list of values enclosed in square brackets.
So, a regex like \[(\s?[0-9]+,?)*\s?\] will match this output:

jq: unnesting records and mixing fields from both record levels

I have the following file:
[
{
'id': 1,
'arr': [{'x': 1,
{'x': 2}]
},
{
'id': 2,
'arr': [{'x': 3},
{'x': 4}]
}
]
How can I transform it into the following form using jq?
[
{'id': 1, 'x': 1},
{'id': 1, 'x': 2},
{'id': 2, 'x': 3},
{'id': 2, 'x': 4},
]
Assuming it doesn't get any more complex than that, you could simply do this:
map(del(.arr) + .arr[])
This is under the assumption that you're replacing the arr property of each object with the contents of the items in arr. It's unclear what you're trying to do exactly.
The input shown in the question is not valid JSON. After making some minor changes to make it valid JSON, the following filter produces the output as shown below:
map( (.arr[]|.x) as $x | {id, "x": $x} )
Output:
[
{
"id": 1,
"x": 1
},
{
"id": 1,
"x": 2
},
{
"id": 2,
"x": 3
},
{
"id": 2,
"x": 4
}
]