How to inject the array indices of objects in an array into the objects, using jq - indexing

Given an array of objects, I would like to inject a property with its position in the array.
For example:
[ { "w" : "Hello" }, { "w" : "World } ]
I would like to produce:
[ { "w" : "Hello", p: 0 }, { "w" : "World, p:1 } ]
where p is the zero-based position in the array.
Is there a way to get the index of the element?
I tried this but it is not working:
keys[] as $i | [ .[] | .p= $i ]
I get:
[ { "w" : "Hello", p: 0 }, { "w" : "World, p:0 } ]

You could do it like this:
[ keys[] as $i | .[$i] | .p=$i ]
Alternatively, you could make it work using to_entries like this:
[ to_entries[] | (.value.p=.key).value ]
Both of which yields:
[
{
"w": "Hello",
"p": 0
},
{
"w": "World",
"p": 1
}
]

Here is a solution which uses reduce
reduce keys[] as $i (.; .[$i].p = $i)

Related

Transformation of Json array in Dataweave

How to write Dataweave transformation in Anytime Studio for given input and output of Json array.
Input:
{
"result": [{
"Labels": [{
"value": [{
"fieldName": "firstName",
"value": "John"
},
{
"fieldName": "lastName",
"value": "Doe"
},
{
"fieldName": "fullName",
"value": "John Doe"
}
]
}]
}]
}
Output:
{
"result": [{
"Labels": [{
"value": [{
"firstName": "John",
"lastName": "Doe",
"fullName": "John Doe"
}]
}]
}]
}
https://docs.mulesoft.com/dataweave/2.4/dw-core-functions-reduce Reduce function might be the one should be used
Thank you in advance
You can just use map to map all the arrays to required format. For the value part you can map the values as fieldName: value array and deconstruct them to an object by wrapping the array around parentheses
%dw 2.0
output application/json
---
{
result: payload.result map ((item) -> {
Labels: item.Labels map ((label) -> {
value: [
{
(label.value map ((field) ->
(field.fieldName): field.value
)) //wrap the array, i.e. lavel.value map ... in parentheses so that it will give you individual key pair.
}
]
})
})
}
You can try below if you are aware that the keyNames will not change:
%dw 2.0
output application/json
---
payload update {
case res at .result -> res map (res, resIndex) -> (res update {
case lbl at .Labels -> lbl map (lbl, lblIndex) -> (lbl update {
case val at .value -> [
(val reduce ((item, acc = {}) -> acc ++ {
(item.fieldName): (item.value)
}))
]
}
)
}
)
}
Here's 2 caveats and a solution. Your input and output files, both are not valid JSON.
Input file, in your "result" object, "Labels" need curly braces {} since they are objects. Key-value pairs should look like this {key:value} not like that key:value
Output file, inside your "value" arrays, key-value pairs need to have the curlies {key:value}
So here's a valid JSON version of your input
{
"result": [
{"Labels": [
{
"value": [
{"fieldName": "firstName","value": "John"},
{"fieldName": "lastName","value": "Doe"},
{"fieldName": "fullName","value": "John Doe"}
]
}
]},
{"Labels": [
{
"value": [
{"fieldName": "firstName","value": "John"}
]
}
]}
]}
Here's a solution
%dw 2.0
import keySet from dw::core::Objects
// this is "result"
var layer1key = keySet(payload)[0]
// this is "Labels" and grabs the first Labels, so assumes Labels doesn't change
var layer2 = payload[layer1key]
var layer2key = keySet(layer2[0])[0]
// this is "value"
var layer3 = layer2[layer2key]
var layer3key = keySet(layer3[0][0])[0]
// this is "fieldName" and "value"
var layer4 = layer3 map (x) -> x['value']
var data1 = ((layer1key) : layer4 map (x) -> {
(layer2key): x map (y) -> {
(layer3key): y map (z) -> {
(z['fieldName']):z['value']
}
}
})
output application/json
---
data1
And a valid JSON version of your output
{
"result": [
{
"Labels": [
{
"value": [
{
"firstName": "John"
},
{
"lastName": "Doe"
},
{
"fullName": "John Doe"
}
]
}
]
},
{
"Labels": [
{
"value": [
{
"firstName": "John"
}
]
}
]
}
]
}

Error while matchig nested json array in Karate

Can anybody help me with the below error? I am not sure what I am missing. I guess something very simple I am missing.
assertion failed: path: $[0].drives[*], actual: [{"partitionData":[{"label":"Recovery"},{"label":""},{"label":"New Volume"},{"label":""}]}], expected: {partitionData=[{"label":"#present"}]}, reason: actual value does not contain expected
Below is my schema code:
* set schema
| path | 0 |
| drives | [{"partitionData": [{"label":"#present"}] }] |
Below is the output:
[
{
"drives": [
{
"partitionData": [
{
"label": "Recovery"
},
{
"label": ""
},
{
"label": "New Volume"
},
{
"label": ""
}
]
}
]
}
]
And match each output contains schema[0]
Since your question is confusing, here is a simple example. Don't use set if not needed.
* def schema = { "partitionData": [ { "label" : "#present" } ] }
* def response = { drives: [ { "partitionData": [ { "label" : "foo" } ] } ] }
* match each response.drives == schema

Use a jq range variable to feed into a new jq filter

I have some JSON that looks like this:
{
"vertices": [
{
"id": 71597,
"ns": "ca",
"alias": "polarized"
},
{
"id": 129748,
"ns": "av",
"name": "Polarized"
},
{
"id": 129898,
"ns": "av",
"name": "False"
}
],
"edgeGroups": {
"hasAttributeValue": [
[
0,
1
],
[
0,
2
]
]
}
}
The various entries in .vertices are related by their array index. So in this case, the first vertex (id: 71597 - with an array index of 0) has attribute values 129748 and 129898 (with array indices 1 and two respectively).
I can get the array index for the attribute I'm searching for with the following jq filter:
.vertices | range(0;length) as $i | select(.[$i].alias=="polarized" and .[$i].ns=="ca") | $i
That returns an $i value of 0, since the object with alias "polarized" is the first item in the array. You can try it out here on jq play:
https://jqplay.org/s/DsHYi7ixyn
Now I want to use that $i value in a different filter, so instead of outputting 0 it outputs something like the result of this:
.edgeGroups.hasAttributeValue[] | select(.[0] == 0)
I've tried using the pipe operator like this but it just gives me an error:
.vertices | range(0;length) as $i | select(.[$i].alias=="polarized" and .[$i].ns=="ca") | .edgeGroups.hasAttributeValue[] | select(.[0] == $i)
If I could understand how to use the $i in a chained filter, I think I could solve my main goal, which is to chain several filters together so that I can get all the items associated with the 71597 object - i.e.
{
"id": 129748,
"ns": "av",
"name": "Polarized"
},
{
"id": 129898,
"ns": "av",
"name": "False"
}
Thanks for any help in advance!
Your jq filter could be fixed with a couple of parentheses:
(.vertices
| range(0;length) as $i
| select(.[$i].alias=="polarized" and .[$i].ns=="ca")
| $i) as $i
| .edgeGroups.hasAttributeValue[]
| select(.[0] == $i)

access Object/Key-value pair from dictionary

I have the following dictionary
{
"b3e0aded-d57b-4159-9c33-c8b006282334" : {
"57646099-b717-4a2b-b9eb-2935548ae954" : [
"yes"
]
},
"1b186bc7-52c4-4b87-a97f-cc52054aad24" : {
"aba16653-bda0-4e89-b1c8-63df6faa7c10" : [
"yes"
]
},
"d765038e-e85a-495d-9932-170852fbd86e" : {
"aba16653-bda0-4e89-b1c8-63df6faa7c10" : [
"yes"
],
"57646099-b717-4a2b-b9eb-2935548ae954" : [
"yes"
],
"957bdaba-b23d-4243-8384-62dfa46f0656" : "play"
},
"2a8dd370-2f7e-4c8e-93d5-21102fbc82fd" : {
"aba16653-bda0-4e89-b1c8-63df6faa7c10" : [
"yes"
]
}
}
How to get each object say
"b3e0aded-d57b-4159-9c33-c8b006282334" : {
"57646099-b717-4a2b-b9eb-2935548ae954" : [
"yes"
]
}
OR
"d765038e-e85a-495d-9932-170852fbd86e" : {
"aba16653-bda0-4e89-b1c8-63df6faa7c10" : [
"yes"
],
"57646099-b717-4a2b-b9eb-2935548ae954" : [
"yes"
]
from this NSDictionary?
use for each in loop to get the full value. i.e
let dict = your dictionary
for each in dict {
print(each)
}
You can use objectForKey: to read the value for a key:
id value = [dict objectForKey:#"b3e0aded-d57b-4159-9c33-c8b006282334"]
Which can be expressed more concisely using square bracket notation:
id value = dict[#"b3e0aded-d57b-4159-9c33-c8b006282334"]
If you then want an object containing just that key mapped to its value then the easiest thing to do is just to construct a new object with the key and value:
id key = #"b3e0aded-d57b-4159-9c33-c8b006282334";
id value = dict[key];
id result = #{ key: value }

How to query mongodb with “like” for number data type? [duplicate]

I want to regex search an integer value in MongoDB. Is this possible?
I'm building a CRUD type interface that allows * for wildcards on the various fields. I'm trying to keep the UI consistent for a few fields that are integers.
Consider:
> db.seDemo.insert({ "example" : 1234 });
> db.seDemo.find({ "example" : 1234 });
{ "_id" : ObjectId("4bfc2bfea2004adae015220a"), "example" : 1234 }
> db.seDemo.find({ "example" : /^123.*/ });
>
As you can see, I insert an object and I'm able to find it by the value. If I try a simple regex, I can't actually find the object.
Thanks!
If you are wanting to do a pattern match on numbers, the way to do it in mongo is use the $where expression and pass in a pattern match.
> db.test.find({ $where: "/^123.*/.test(this.example)" })
{ "_id" : ObjectId("4bfc3187fec861325f34b132"), "example" : 1234 }
I am not a big fan of using the $where query operator because of the way it evaluates the query expression, it doesn't use indexes and the security risk if the query uses user input data.
Starting from MongoDB 4.2 you can use the $regexMatch|$regexFind|$regexFindAll available in MongoDB 4.1.9+ and the $expr to do this.
let regex = /123/;
$regexMatch and $regexFind
db.col.find({
"$expr": {
"$regexMatch": {
"input": {"$toString": "$name"},
"regex": /123/
}
}
})
$regexFinAll
db.col.find({
"$expr": {
"$gt": [
{
"$size": {
"$regexFindAll": {
"input": {"$toString": "$name"},
"regex": "123"
}
}
},
0
]
}
})
From MongoDB 4.0 you can use the $toString operator which is a wrapper around the $convert operator to stringify integers.
db.seDemo.aggregate([
{ "$redact": {
"$cond": [
{ "$gt": [
{ "$indexOfCP": [
{ "$toString": "$example" },
"123"
] },
-1
] },
"$$KEEP",
"$$PRUNE"
]
}}
])
If what you want is retrieve all the document which contain a particular substring, starting from release 3.4, you can use the $redact operator which allows a $conditional logic processing.$indexOfCP.
db.seDemo.aggregate([
{ "$redact": {
"$cond": [
{ "$gt": [
{ "$indexOfCP": [
{ "$toLower": "$example" },
"123"
] },
-1
] },
"$$KEEP",
"$$PRUNE"
]
}}
])
which produces:
{
"_id" : ObjectId("579c668c1c52188b56a235b7"),
"example" : 1234
}
{
"_id" : ObjectId("579c66971c52188b56a235b9"),
"example" : 12334
}
Prior to MongoDB 3.4, you need to $project your document and add another computed field which is the string value of your number.
The $toLower and his sibling $toUpper operators respectively convert a string to lowercase and uppercase but they have a little unknown feature which is that they can be used to convert an integer to string.
The $match operator returns all those documents that match your pattern using the $regex operator.
db.seDemo.aggregate(
[
{ "$project": {
"stringifyExample": { "$toLower": "$example" },
"example": 1
}},
{ "$match": { "stringifyExample": /^123.*/ } }
]
)
which yields:
{
"_id" : ObjectId("579c668c1c52188b56a235b7"),
"example" : 1234,
"stringifyExample" : "1234"
}
{
"_id" : ObjectId("579c66971c52188b56a235b9"),
"example" : 12334,
"stringifyExample" : "12334"
}
Now, if what you want is retrieve all the document which contain a particular substring, the easier and better way to do this is in the upcoming release of MongoDB (as of this writing) using the $redact operator which allows a $conditional logic processing.$indexOfCP.
db.seDemo.aggregate([
{ "$redact": {
"$cond": [
{ "$gt": [
{ "$indexOfCP": [
{ "$toLower": "$example" },
"123"
] },
-1
] },
"$$KEEP",
"$$PRUNE"
]
}}
])