Split array inside JSON with JOLT - jolt

I have a JSON look like:
[
{
"mainId": 12854,
"subIds": [
25,
26,
27
]
}
]
I want to split values inside subIds to create diffrent rows.
Can I get expected result with JOLT?
[
{
"mainId": 12854,
"subId": 25
},
{
"mainId": 12854,
"subId": 26
},
{
"mainId": 12854,
"subId": 27
}
]

You can walk through the indexes of subIds array while grabbing the value of mainId by #(2,mainId) in order to going up the three two levels, and using [&1] as common factor to reach those indexes such as
[
{
"operation": "shift",
"spec": {
"*": {
"subIds": {
"*": {
"#": "[&1].subId",
"#(2,mainId)": "[&1].mainId"
}
}
}
}
}
]

Related

How can I filter records with multiple $in condition (some are optional $in) with arrays of string? Mongoose/MongoDB

You can see my Mongodb Records at last... I am now trying to implement search functionality,
I mad checkbox filtration for my project and below I listed those arrays after I clicked multiple checkboxes (see 1, 2 and 3).
I tried in aggregate with multiple match queries with $in, but it doesn't worked. Below arrays are used to check the records.
for example:
["Restaurant", "Mall"] need to check with "commercialType" in records, at the same time ["AC Rooms", "3 Phase Electricity"] need to check with "propertyFeatures.name" in records.. so all matching records must display if records exist with those filtrations.
I tried with multiple $in queries like this, but it gives empty records.
"$match": {
"commercialType": {
"$in": ["Restaurant", "Hotel"]
},
{
"propertyFeatures.name": {
"$in": ['AC Rooms']
}
},
... other match filters
}
1. Below Array is used to find commercialType (field in doc)
[
'Restaurant',
'Office space',
'Hotel'
]
2. Below Array is used to find landType (field in doc)
[
'Bare land',
'Beachfront land',
'Coconut land'
]
3. Below Array is used to find "propertyFeatures.name" (field in doc)
[
'AC Rooms',
'3 Phase Electricity',
'Hot Water'
]
[
{
"_id": {
"$oid": "6343b68edf5e889a575c8502"
},
"propertyType": "House",
"propertyFeatures": [
{
"id": 1,
"name": "AC Rooms",
"value": true
}
]
},
{
"_id": {
"$oid": "6343b68edf5e889a575c8502"
},
"propertyType": "Land",
"landType": "Bare land",
"propertyFeatures": [
{
"id": 1,
"name": "Wider Road",
"value": true
}
]
},
{
"_id": {
"$oid": "6343b68edf5e889a575c8502"
},
"propertyType": "Commercial",
"commercialType": "Restaurant",
"propertyFeatures": [
{
"id": 1,
"name": "3 Phase Electricity",
"value": true
}
]
}
]
You are probably missing $or operator, so your example pipeline becomes
[
{"$match": {
"$or": [
{
"commercialType": {
"$in": ["Restaurant", "Hotel"]
},
{
"propertyFeatures.name": {
"$in": ['AC Rooms']
}
}
]
}
]
MongoDB docs: https://www.mongodb.com/docs/manual/reference/operator/aggregation/or/#error-handling

MongoDB Inner Array Query

I have the following Mongo Document. I need the output for all SID =100 as shown. How can this be achieved. Tried different ways.
As seen, there are multiple array levels. The input has collection of SIDs with all products.
Input
[
{
"_id": "123456",
"Continent": {
"Country": [
[
"US",
{
"State": [
[
100,
{
"Product": "Corn",
"SID": 100
}
],
[
200,
{
"Product": "Maze",
"SID": 200
}
],
[
100,
{
"Product": "Corn-HB",
"SID": 100
}
]
],
}
]
]
}
}
]
Here the out has only the collection of SID = 100, but it preserves the input format
Output
[
{
"_id": "123456",
"Continent": {
"Country": [
[
"US",
{
"State": [
[
100,
{
"Product": "Corn",
"SID": 100
}
],
[
100,
{
"Product": "Corn-HB",
"SID": 100
}
]
],
}
]
]
}
}
]
As mentioned in the question comments, this data design is a bit odd but a solution can be achieved using the $function function (starting in v4.4 Sep 2020) which avoids maps of maps of reduce, etc.:
var keeper_sid = 100;
db.foo.aggregate([
{$replaceRoot: {newRoot: {$function: {
body: function(obj, keeper) {
var country_arr = obj['Continent']['Country'];
for(var n1 = 0; n1 < country_arr.length; n1++) {
var tuple1 = country_arr[n1];
var state_arr = tuple1[1]['State'];
// Walk the State array backwards to ease deletions.
for(var n2 = state_arr.length - 1; n2 >= 0; n2--) {
var tuple2 = state_arr[n2];
if(tuple2[1]['SID'] != keeper) {
state_arr.splice(n2,1);
}
}
}
return obj;
},
args: [ "$$ROOT", keeper_sid ],
lang: "js"
}}
}}
]);
This is straightforward but it does make assumptions about the structure e.g. extracting the second ([1]) item from the "tuples." The code can be reduced a bit more but intermediate variables (tuple1,2) are shown to make the whole thing a little more clear.

JSON array transform with JOLT

I receive following JSON from some REST API:
{
"operation_id" : [ 1405494, 1409934, 1420753 ],
"operation_status" : "success"
}
I want to split operation_id from array to get 1 by 1 value and create new JSON which should look like:
{
"operationsStatus": [
{
"operation_id": 1405494,
"operation_status": "success"
},
{
"operation_id": 1409934,
"operation_status": "success"
},
{
"operation_id": 1420753,
"operation_status": "success"
}
]
}
Can I do it with JOLT spec?
You can walk through the operation_id array by using a shift transformation such as
[
{
"operation": "shift",
"spec": {
"*": {
"operation_id": {
"*": {
"#": "operationsStatus[&1].&2",
"#(2,operation_status)": "operationsStatus[&1].operation_status"
}
}
}
}
}
]
the Result of the demo on https://jolt-demo.appspot.com/

Jolt for complex JSON transform

Extracting values from first array element and second element and joining both.
Input String:
[
{
"creationDate": "2020-04-01T14:14:32.685+0000",
"factValues": [
{
"Factname": "Medicine",
"factvalue": "1234556",
"sourcePguid": "1"
},
{
"Factname": "Journal",
"factvalue": "123455",
"sourcePguid": "1"
}
]
},
{
"creationDate": "2020-04-01T14:14:32.685+0000",
"factValues": [
{
"Factname": "chemical",
"factvalue": "123455567",
"sourcePguid": "2"
},
{
"Factname": "Rubber",
"factvalue": "123455435",
"sourcePguid": "3"
}
]
}
]
Output excepted:
{
{
"sourcePguid" : "1",
"Medicine":"1234556",
"Journal":"123455"
}, {
"sourcePguid" : "2",
"chemical":"123455567",
"Rubber":"123455435"
}
}
Kindly help me to achieve the expected output.json in spec.json. The spec is not transforming as expected output. I want learn how to use attributes inside the string parser.It would be great.
Hope this might help,
[
{
"operation": "shift",
"spec": {
"*": {
"factValues": {
"*": {
"sourcePguid": "&3.sourcePguid",
"#(0,factvalue)": "&3.#Factname"
}
}
}
}
}, {
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"sourcePguid": "=firstElement(#(1,sourcePguid))"
}
}
}
]
Yet another answer using JSONata
For java: https://github.com/IBM/JSONata4Java
$.factValues{
sourcePguid: {
"sourcePguid": $distinct(sourcePguid),
Factname:factvalue
}
} ~> $each(function($v){$v})

ElasticSearch - Get different types from different indices

I have two indices: A and B.
A has the following types: car, motorbike and van.
B has the following types: bus, car and pickup.
I want to be able to have a single query which gets motorbike and van from A and car and pickup from B.
I want to use a filter to do this and currently, I have:
.filter(
not(
should(
termsQuery("key", Seq("car", "bus"))
)
)
)
But obviously, this will filter car for both indices. I know I can do two separate queries for each index and filter different types for each but I want to avoid this if possible.
Is it possible to do what I am trying to do in a single query?
You can search on index and type by using the special fields _index and _type so once you know that, it's just a matter of putting together a boolean query.
search("_all").query(
boolQuery().should(
boolQuery().must(
termQuery("_index", "A"),
termsQuery("_type", "motorbike", "van")
),
boolQuery().must(
termQuery("_index", "B"),
termsQuery("_type", "car", "pickup")
)
)
)
You can do something like this.
GET _search
{
"query": {
"bool": {
"should": [
{
"bool": {
"filter": [
{
"term": {
"_index": {
"value": "A"
}
}
},
{
"terms": {
"_type": ["motorbike","van"]
}
}
]
}
},
{
"bool": {
"filter": [
{
"term": {
"_index": {
"value": "B"
}
}
},
{
"terms": {
"_type": ["car","pickup"]
}
}
]
}
}
]
}
}
}