JOLT: array item string to integer conversion - jolt

How can I transform a specific item in an array to integer? In the following example, I want only the 3rd element 456 to be converted to integer, and 123 to be left intact:
input:
{
"arr": [
"hello",
"123",
"456"
]
}
Trying this spec:
[
{
"operation": "modify-overwrite-beta",
"spec": {
"arr": "=toInteger"
}
}
]
I get actual output:
{
"arr": [
"hello",
123,
456
]
}
However, the desired output should look like this:
expected output:
{
"arr": [
"hello",
"123",
456
]
}
Thank you,
Gerasimos

You should get
{
"arr": [
"hello",
123,
456
]
}
for the current case. Just need to restrict to the index(2) of the desired element within the spec such as
[
{
"operation": "modify-overwrite-beta",
"spec": {
"arr": {
"[2]": "=toInteger"
}
}
}
]
in order to get the desired result, that's :
{
"arr": [
"hello",
"123",
456
]
}

Related

How to use $subtract along with conditions to use a default value from an array, if null?

I'm trying to subtract values from final array and start array in my aggregation pipeline. But there are certain exceptional cases that needs some additional logic before subtraction.
Expected Output:
I need to subtract nth value of startarray from nth value of final array
And then, get the total sum of subtracted values
Exceptional Cases:
If nth value of start array is NULL, use a start_default value(from the query)
If nth value of final array is NULL, use value from the final_default array
After some of the aggregation stages, my MongoDB document has this format:
Assuming that start_default value = 1
I have commented the way I expect to perform subtractions in each of the group
{
"data": [
{
"key": "TP-1",
"status_map": [
{
"status": "Closed",
"final": [
6,
3
], // Expected Output
"start": [ // sum:6 [(6-2)+(3-1(start_default))=4+2]
2
],
"final_default": [
4
]
},
{
"status": "Done",
"final": [
4
], // Expected Output
"start": [ // sum:2 [(4-3)+(2(final_default)-1)=1+1]
3,
1
],
"final_default": [
2
]
}
]
},
{
"key": "TP-2",
"status_map": [
{
"status": "Closed",
"final": [
1,
5
], // Expected Output
"start": [], //sum:4 [(1-1(start_default))+(5-1(start_default))=0+4]
"final_default": [
3
]
},
{
"status": "Done",
"final": [], // Expected Output
"start": [ //sum:3 [(5(final_default)-3)+(5(final_default)-4)=2+1]
3,
4
],
"final_default": [
5
]
}
]
}
]
}
Here is my expected output assuming that start_default value = 1
{
"data": [
{
"key": "TP-1",
"status_map": [
{
"status": "Closed",
"sum": 6 //[(6-2)+(3-1(start_default))=4+2]
{
"status": "Done",
"sum": 2 //[(4-3)+(2(final_default)-1)=1+1]
}
]
},
{
"key": "TP-2",
"status_map": [
{
"status": "Closed",
"sum": 4 //[(1-1(start_default))+(5-1(start_default))=0+4]
},
{
"status": "Done",
"sum": 3 //[(5(final_default)-3)+(5(final_default)-4)=2+1]
}
]
}
]
}
How to achieve this use case?
You can start with double $map to rewrite your nested array. You'll also need $reduce since you'll be converting an array into scalar value. Since you need to "pair" two arrays, there's a perfect operator called $zip which can be used even if arrays have different lengths. Pairing final and start for the first subdocument will return:
[ [ 6,2 ], [ 3, null ] ]
which is great because you can use $ifNull to provide a default value.
Your aggregation can look like below:
db.collection.aggregate([
{
$project: {
data: {
$map: {
input: "$data",
as: "d",
in: {
key: "$$d.key",
status_map: {
$map: {
input: "$$d.status_map",
as: "sm",
in: {
status: "$$sm.status",
sum: {
$reduce: {
input: {
$zip: {
inputs: [ "$$sm.final", "$$sm.start" ],
useLongestLength: true
}
},
initialValue: 0,
in: {
$add: [
"$$value",
{
$subtract: [
{ $ifNull: [ { $arrayElemAt: [ "$$this", 0 ] }, { $arrayElemAt: [ "$$sm.final_default" , 0] } ] },
{ $ifNull: [ { $arrayElemAt: [ "$$this", 1 ] }, 1 ] }
]
}
]
}
}
}
}
}
}
}
}
}
}
}
])
Mongo Playground

Mongo $addField For nested structured data

I have a result like below, Is there any way I can change the _id value which is the same for the all nested data. I want to rename each id with some other name not simply _id
{
"items": [
{
"_id": "5bd1a3da2901d60f9edc4d10",
"addons": [
{
"_id": "5bd1a3da2901d60f9edc4d96",
"options": [
{
"_id": "5bd1a3da2901d60f9edc4d98",
}
],
}
]
}
]
}
Here in the above code, I tried $addfields attribute but it works fine only for the topmost nesting
Here is the code I've tried:
Items.aggregate([
{
$match: { _id: '123'}
},
{ $addFields: { item_id: "$_id" ,
"addons.addon_id" : "$addons._id" ,
"addons.options.options_id" : "$addons.options._id"
}
},
{
$project: {
_id: 0
}
},
],
This code works fine and added item_id in the root element but added addon and option_id as an array value,
{
"item_list": [
{
"_id": "5bd1a3da2901d60f9edc4d10",
"addons": [
{
"_id": "5bd1a44b2901d60f9edc4d9a",
"options": [
{
"_id": "5bd1a44b2901d60f9edc4d9b",
"options_id": [
[
"5bd1a44b2901d60f9edc4d9b"
]
]
}
],
"addon_id": [
"5bd1a44b2901d60f9edc4d9a"
]
}
]
}
]
}
I got something like this a nested array of addon_id and options_id, I want it to be a simple string and not array,
{
"item_list": [
{
"_id": "5bd1a3da2901d60f9edc4d10",
"addons": [
{
"_id": "5bd1a44b2901d60f9edc4d9a",
"options": [
{
"_id": "5bd1a44b2901d60f9edc4d9b",
"options_id": "5bd1a44b2901d60f9edc4d9b"
}
],
"addon_id": "5bd1a44b2901d60f9edc4d9a"
}
]
}
]
}
Am expecting the above result.

Jolt convert array keys

I want to convert keys in array json by using jolt
Input
[
{
"TestString": "AGC",
"TestNumber": "3"
},
{
"TestString": "DDD",
"TestNumber": "2"
}
]
Out put:
[
{
"test_string": "AGC",
"test_number": "3"
},
{
"test_string": "DDD",
"test_number": "2"
}
]
What is jolt spec will be?
[{
"operation": "shift",
"spec": {
"*": {
"TestString": "[&1].test_string",
"TestNumber": "[&1].test_number"
}
}
}]

How will the JOLT spec look to achieve desired result with the following input?

I am having troubles transforming JSON payload into the desired document.
I have following input:
{
"events": [
{
"recipientId": "r0001"
},
{
"recipientId": "r0002"
}
],
"networkResponseTime": 1234
}
Desired output:
{
"events": [
{
"recipientIds": "r0001",
"networkResponseTime": 1234"
},
{
"recipientIds": "r0002",
"networkResponseTime": 1234"
}
]
}
How will the JOLT spec look like for this example?
So far I have smth like this:
[{
"operation": "shift",
"spec": {
"events": {
"*": {
"recipientId": "events[&1].recipientIds"
}
}
}
}]
Spec
[{
"operation": "shift",
"spec": {
"events": {
"*": {
"recipientId": "events[&1].recipientIds",
//
// go back up to the root of the tree, and then
// come back down the key "networkResponseTime", and
// send it's value to "events[&1].networkResponseTime"
"#(2,networkResponseTime)": "events[&1].networkResponseTime"
}
}
}
}]

Match a specific item in a collection using MongoDB aggregation query

In the following document, I'd like to find the table object which has the column matching the criteria
(label is 'abc' or (name is 'abc' and label is empty))
{
"tables": [
{
"name": "table1",
"columns": [
{
"name": "abc",
"label": "xyz"
},
{
"name": "def",
"label": ""
}
]
},
{
"name": "table2",
"columns": [
{
"name": "xxx",
"label": "yyy"
},
{
"name": "zzz",
"label": "abc"
}
]
}
]
}
The expected answer is table2 object.
The following query returns both table1 and table2. I think the 'match' clause is applied to the entire column array not column by column. I'd like to get the table object as the final result So unwinding at column level is not an option.
db.getCollection('test').aggregate(
{$unwind : "$tables"},
{"$match":
{"$or":
[
{"tables.columns.label": "abc"},
{"tables.columns.name":"abc", "tables.columns.label": ""}
]
}
}
)
How do I match column by column?
You should use the $elemMatch operator:
db.getCollection('test').aggregate(
{
$unwind: "$tables"
},
{
$match:
{
"$or":
[
{
"tables.columns.label": "abc"
},
{
"tables.columns":
{
$elemMatch:
{
"name": "abc",
"label": ""
}
}
}
]
}
}
)