Jolt Spec - Need help in getting Flattened Array - json

I am having some trouble with flattening the JSON. I have looked at examples and didn't get any closer as to what is mentioned above. I need to transform a JSON structure by using a JOLT spec. I use https://jolt-demo.appspot.com to test the following below.
JSON Input for a sample :
{
"metadata": {
"timestamp": "XXXXX"
},
"data": {
"product": {
"id": "XXXXX"
},
"storageLocations": [
{
"id": "XXXXX",
"stocks": [
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
},
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
},
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
}
],
"dateModified": "XXXXX"
},
{
"id": "XXXXX",
"stocks": [
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
},
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
},
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
}
],
"dateModified": "XXXXX"
},
{
"id": "XXXXX",
"stocks": [
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
},
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
},
{
"stockStatus": "XXXXX",
"quantity": [
{
"uom": "XXXXX",
"isoUom": "XXXXX",
"amount": "XXXXX"
}
]
}
],
"dateModified": "XXXXX"
}
],
"dateModified": "XXXXX",
"temporaryNegativeStock": "XXXXX"
}
}
the tried Jolt Spec is :
[
{
"operation": "shift",
"spec": {
"data": {
"storageLocations": {
"*": {
"#(3,metadata.timestamp)": "[&1].LastUpdated",
"#(2,product.id)": "[&1].MaterialCode",
"#(2,product.baseUoM)": "[&1].BaseUoM",
"#(2,product.isoBaseUom)": "[&1].ISOBaseUoM",
"#(2,location.id)": "[&1].LocationId",
"#(id)": "[&1].StorageLocationId",
"#(dateModified)": "[&1].StorageLocationLastUpdated",
"stocks": {
"*": {
"quantity": {
"*": {
"#(amount)": "[&5].StockAmount",
"#(isoUom)": "[&5].StockISOUoM",
"#(uom)": "[&5].StockUoM",
"#(2,stockStatus)": "[&5].StockStatus"
}
}
}
}
}
}
}
}
}
]
Ouput we are getting
[
{
"LastUpdated": "XXXXX",
"MaterialCode": "na-XXXXX",
"StorageLocationId": "XXXXX",
"StorageLocationLastUpdated": "XXXXX",
"StockAmount": [
"0.000",
"0.000",
"0.000"
],
"StockISOUoM": [
"XXXXX",
"XXXXX",
"XXXXX"
],
"StockUoM": [
"XXXXX",
"XXXXX",
"XXXXX"
],
"StockStatus": [
"XXXXX",
"XXXXX",
"XXXXX"
]
},
{
"LastUpdated": "XXXXX",
"MaterialCode": "na-XXXXX",
"StorageLocationId": "XXXXX",
"StorageLocationLastUpdated": "XXXXX",
"StockAmount": [
"0.000",
"0.000",
"0.000"
],
"StockISOUoM": [
"XXXXX",
"XXXXX",
"XXXXX"
],
"StockUoM": [
"XXXXX",
"XXXXX",
"XXXXX"
],
"StockStatus": [
"XXXXX",
"XXXXX",
"XXXXX"
]
},
{
"LastUpdated": "XXXXX",
"MaterialCode": "na-XXXXX",
"StorageLocationId": "XXXXX",
"StorageLocationLastUpdated": "XXXXX",
"StockAmount": [
"0.000",
"0.000",
"0.000"
],
"StockISOUoM": [
"XXXXX",
"XXXXX",
"XXXXX"
],
"StockUoM": [
"XXXXX",
"XXXXX",
"XXXXX"
],
"StockStatus": [
"XXXXX",
"XXXXX",
"XXXXX"
]
}
]
Need help in writing a jolt spec so that we get a flattened Array

You can add one more shift transformation to separate the content of the currently generated three objects triple so as to generate 3 x 3 = 9 objects by walking along with a component of the arrays start with Stock(I've picked StockStatus in this case), then prune all of the key names through use of an extra shift transformation such as
[
{
"operation": "shift",
<body of the current spec>
},
{
"operation": "shift",
"spec": {
"*": {
"StockStatus": {
"*": {
"#(2,LastUpdated)": "&3.&1.LastUpdated",
"#(2,MaterialCode)": "&3.&1.MaterialCode",
"#(2,StorageLocationId)": "&3.&1.StorageLocationId",
"#(2,StorageLocationLastUpdated)": "&3.&1.StorageLocationLastUpdated",
"#(2,StockAmount[&])": "&3.&1.StockAmount",
"#(2,StockISOUoM[&])": "&3.&1.StockISOUoM",
"#(2,StockUoM[&])": "&3.&1.StockUoM",
"#": "&3.&1.StockStatus"
}
}
}
}
},
{
"operation": "shift",
"spec": {
"*": {
"*": ""
}
}
}
]
where &3 stands for going three levels up in order to reach the uppermost indices(they are 0,1,2), which are one level above the StockStatus key's level, and &1 to reach the indices of StockStatus array(they are 0,1,2 too) to separate each element groups into 3 x 3 = 9 different objects. The ampersands within the #(2,Stock....[&]) keys represent looking up the indices of StockStatus array as well.

Related

Inserting a Complex Nested JSON Column in MySQL

Here is my use case :-
I am trying to get the deployment details in a JSON format using :
kubectl get deployment -o json depl_name
and inserting result back to a column: meta_data in MySQL. The column data type is json . But the insert statement is failing with error :-
ERROR 3140 (22032): Invalid JSON text: "Missing a comma or '}' after an object member." at position 1035 in value for column
Here is my entire JSON :-
{
"uuid": {
"view": "demoBoard",
"demo": [
{
"serviceName": "wordpress-backend",
"configurations": {
"ec2_iam": {
"user": [],
"roles": null,
"permissions": null
}
},
"deployment_config": {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"annotations": {
"deployment.kubernetes.io/revision": "6",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"app\":\"wordpress-backend\",\"wordpress_app_id\":\"w26\"},\"name\":\"wordpress-backend\",\"namespace\":\"wordpress\"},\"spec\":{\"selector\":{\"matchLabels\":{\"app\":\"wordpress-backend\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"wordpress-backend\",\"wordpress_app_id\":\"w26\"}},\"spec\":{\"containers\":[{\"envFrom\":[{\"configMapRef\":{\"name\":\"wordpress-backend-config\"}}],\"image\":\"docker-image\",\"imagePullPolicy\":\"IfNotPresent\",\"name\":\"wordpress-backend\",\"ports\":[{\"containerPort\":8000}],\"resources\":{},\"volumeMounts\":[{\"mountPath\":\"/tmp/me/cloud\",\"name\":\"my-key\"}]}],\"imagePullSecrets\":[{\"name\":\"my-json\"}],\"volumes\":[{\"name\":\"my-cloud-key\",\"secret\":{\"defaultMode\":123,\"secretName\":\"my-key\"}}]}}}}\n"
},
"creationTimestamp": "2022-09-12T13:56:34Z",
"generation": 7,
"labels": {
"app": "wordpress-backend",
"wordpress_app_id": "w26"
},
"name": "wordpress-backend",
"namespace": "wordpress",
"resourceVersion": "v2",
"uid": "0da99b29"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app": "wordpress-backend"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": "25%",
"maxUnavailable": "25%"
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"app": "wordpress-backend",
"wordpress_app_id": "267"
}
},
"spec": {
"containers": [
{
"envFrom": [
{
"configMapRef": {
"name": "wordpress-backend-config"
}
}
],
"image": "docker.io/my-image",
"imagePullPolicy": "IfNotPresent",
"name": "wordpress-backend",
"ports": [
{
"containerPort": 8000,
"protocol": "TCP"
}
],
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/my/path/cloud",
"name": "my-key"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"imagePullSecrets": [
{
"name": "my-key"
}
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"name": "my-key",
"secret": {
"defaultMode": 123,
"secretName": "sampleKeyName"
}
}
]
}
}
},
"status": {
"availableReplicas": 1,
"conditions": [
{
"lastTransitionTime": "2022-09-29T15:11:14Z",
"lastUpdateTime": "2022-09-29T15:11:14Z",
"message": "Deployment has minimum availability.",
"reason": "MinimumReplicasAvailable",
"status": "True",
"type": "Available"
},
{
"lastTransitionTime": "2022-09-12T14:20:35Z",
"lastUpdateTime": "2022-09-30T14:13:08Z",
"message": "ReplicaSet \"wordpress-backend-abc123\" has successfully progressed.",
"reason": "NewReplicaSetAvailable",
"status": "True",
"type": "Progressing"
}
],
"observedGeneration": 7,
"readyReplicas": 1,
"replicas": 1,
"updatedReplicas": 1
}
}
}
]
}
}
I guess, because of escape sequence in below line causing the failure :-
"message": "ReplicaSet \"wordpress-backend-abc123\" has successfully progressed.", tried removing that, but no luck.

Generic Jolt Spec for Multiple Input JSON - Multiple Inputs

I m having difficulty in writing a jolt spec for different JSON inputs. I need to get a generic jolt spec so that i get a flattened json.
Input 1 : We have a materialMovements array
{
"id": "xxxxx",
},
"status": {
"deliveryComplete": "xxxxx",
],
"overallStatusDetail": "xxxxx",
"overallStatus": "xxxxx"
},
"quantity": {
"target": {
"amount": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
}
},
"dates": {
"plannedFinishDate": "xxxxx",
"plannedStartDate": "xxxxx",
"actualFinishDate": "xxxxx"
},
"consumptionFlag": xxxxx,
"billOfMaterials": "xxxxx",
"deletionIndicator": "",
"routingNumber": "xxxxx",
"mainWorkCenter": "xxxxx",
"orderRecipe": "xxxxx",
"item": {
"number": "xxxxx",
"product": {
"id": "xxxxx",
"number": "xxxxx",
"description": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
},
"goodsReceipt": {
"amount": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
},
"storageLocation": {
"code": "xxxxx",
"description": "xxxxx"
}
},
"reservation": {
"id": "xxxxx",
"number": "xxxxx",
},
"materialMovements": [
{
"id": "xxxxx",
"number": "xxxxx",
"postingDate": "xxxxx",
"items": [
{
"number": "xxxxx",
},
"product": {
"id": "xxxxx",
}
}
]
}
}
],
"sourceSystem": "NA"
}
Input 2 : We dont have a materialmovements array
{
"id": "xxxxx",
},
"status": {
"deliveryComplete": "xxxxx",
],
"overallStatusDetail": "xxxxx",
"overallStatus": "xxxxx"
},
"quantity": {
"target": {
"amount": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
}
},
"dates": {
"plannedFinishDate": "xxxxx",
"plannedStartDate": "xxxxx",
"actualFinishDate": "xxxxx"
},
"consumptionFlag": xxxxx,
"billOfMaterials": "xxxxx",
"deletionIndicator": "",
"routingNumber": "xxxxx",
"mainWorkCenter": "xxxxx",
"orderRecipe": "xxxxx",
"item": {
"number": "xxxxx",
"product": {
"id": "xxxxx",
"number": "xxxxx",
"description": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
},
"goodsReceipt": {
"amount": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
},
"storageLocation": {
"code": "xxxxx",
"description": "xxxxx"
}
},
"reservation": {
"id": "xxxxx",
"number": "xxxxx",
},
"sourceSystem": "NA"
}
I hv used the joltspec for the Input 1 which is working fine, i need it to work for the input 2 also
[
{
"operation": "shift",
"spec": {
"materialMovements": {
"*": {
"#(2,sourceSystem)": "[&1].SourceSystem",
"#(2,number)": "[&1].ProcessOrderNumber",
"#(2,item.number)": "[&1].ProcessOrderLineNumber",
"#(2,item.product.number)": "[&1].MaterialToBeProduced",
"#(2,item.storageLocation.code)": "[&1].StorageLocation",
"#(2,item.goodsReceipt.amount)": "[&1].GoodsReceiptQuantity",
"#(2,locationIdentifier.id)": "[&1].Plant",
"#(2,billOfMaterials)": "[&1].BillOfMaterials",
"#(2,creationDate)": "[&1].CreationDate",
"#(2,dates.plannedFinishDate)": "[&1].PlannedFinishDate",
"#(2,dates.plannedStartDate)": "[&1].plannedStartDate",
"#(2,actualFinishDate)": "[&1].ActualFinishDate",
"#(2,deletionIndicator)": "[&1].DeletionIndicator",
"#(2,quantity.target.amount)": "[&1].OrderQuantity",
"#(2,quantity.target.baseUoM)": "[&1].UOM",
"#(2,quantity.confirmed.amount)": "[&1].ConfirmedQuantity",
"#(2,mainWorkCenter)": "[&1].MainWorkCenter",
"#(2,orderRecipe)": "[&1].OrderRecipe",
"#(2,Message Timestamp)": "[&1].LastModifiedOn",
"#(2,status.overallStatusDetail)": "[&1].StatusDetail",
"#(2,status.overallStatus)": "[&1].Status",
"postingDate": "[&1].ActualDeliveryDate"
}
}
}
}
]
The approach you are following is making it a little more complex :
I am not able to understand the Input Json as it is not proper but I guess this solution will help in resolving your issue :
Input :
{
"quantity": {
"target": {
"amount": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
}
},
"dates": {
"plannedFinishDate": "xxxxx",
"plannedStartDate": "xxxxx",
"actualFinishDate": "xxxxx"
},
"billOfMaterials": "xxxxx",
"deletionIndicator": "",
"routingNumber": "xxxxx",
"mainWorkCenter": "xxxxx",
"orderRecipe": "xxxxx",
"item": {
"number": "xxxxx",
"product": {
"id": "xxxxx",
"number": "xxxxx",
"description": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
},
"goodsReceipt": {
"amount": "xxxxx",
"baseUoM": "xxxxx",
"ISOBaseUoM": "xxxxx"
},
"storageLocation": {
"code": "xxxxx",
"description": "xxxxx"
}
},
"reservation": {
"id": "xxxxx",
"number": "xxxxx"
},
"materialMovements": [
{
"id": "xxxxx",
"number": "xxxxx",
"postingDate": "xxxxx",
"items": [
{
"number": "xxxxx"
},
{
"id": "xxxxx"
}
]
}
],
"sourceSystem": "NA"
}
Jolt Spec :
[
{
"operation": "shift",
"spec": {
"quantity": {
"target": {
"*": "[#4].&"
}
},
"dates": {
"*": "[#3].&"
},
"billOfMaterials": "[#2].&",
"deletionIndicator": "[#2].&",
"routingNumber": "[#2].&",
"mainWorkCenter": "[#2].&",
"orderRecipe": "[#2].&",
"materialMovements": {
"*": {
"id": "[&1].id",
"number": "[&1].number",
"items": {
"*": {
"number": "[&1].no"
}
}
}
}
}
},
//For Flattening Array to Single Json
{
"operation": "shift",
"spec": {
"*": {
"*": "&"
}
}
}
]

How to Add an Object to a Json Array Depending a value of another Key in the File Using JoltTransformationJson in NiFi

This is my first time to use JoltTransformationJson, so I have limited knowledge and experience on that. Please help me with this complicated project.
Request:
when the payment.code <> "paid", I have to do the following two things for the file.
to change the payment.code ="denied" and payment.text ="denied"
to add a JSON object to item.ADJ
When the payment.code =="paid", don't need to change anything.
Input :
{
"resourceType": "E",
"id": "11",
"identifier": [
{
"type": {
"coding": [
{
"system": "sys1",
"code": "aaa"
}
]
},
"value": "212"
},
{
"type": {
"coding": [
{
"system": "sys2",
"code": "RRR"
}
]
},
"value": "367"
}
],
"status": "active",
"created": "2021-08-05T02:43:48+00:00",
"outcome": "complete",
"item": [
{
"sequence": 1,
"product": {
"coding": [
{
"system": "example",
"code": "abc",
"display": "ABC"
}
],
"text": "ABC"
},
"servicedDate": "2021-08-04",
"quantity": {
"value": 60
},
"ADJ": [
{
"category": {
"coding": [
{
"system": "code1",
"code": "code1",
"display": "CODE1"
}
],
"text": "CODE1"
},
"amount": {
"value": 46.45,
"currency": "USD"
}
},
{
"category": {
"coding": [
{
"system": "code2",
"code": "code2",
"display": "CODE2"
}
],
"text": "CODE2"
},
"amount": {
"value": 12.04,
"currency": "USD"
}
}
]
}
],
"payment": {
"type": {
"coding": [
{
"system": "http://payment.com",
"code": "reversed/cancelled"
}
],
"text": "cancelled"
}
}
}
My Expected Output :
{
"resourceType": "E",
"id": "11",
"identifier": [
{
"type": {
"coding": [
{
"system": "sys1",
"code": "aaa"
}
]
},
"value": "212"
},
{
"type": {
"coding": [
{
"system": "sys2",
"code": "RRR"
}
]
},
"value": "367"
}
],
"status": "active",
"created": "2021-08-05T02:43:48+00:00",
"outcome": "complete",
"item": [
{
"sequence": 1,
"product": {
"coding": [
{
"system": "example",
"code": "abc",
"display": "ABC"
}
],
"text": "ABC"
},
"servicedDate": "2021-08-04",
"quantity": {
"value": 60
},
"ADJ": [
{
"category": {
"coding": [
{
"system": "code1",
"code": "code1",
"display": "CODE1"
}
],
"text": "CODE1"
},
"amount": {
"value": 46.45,
"currency": "USD"
}
},
{
"category": {
"coding": [
{
"system": "code2",
"code": "code2",
"display": "CODE2"
}
],
"text": "CODE2"
},
"amount": {
"value": 12.04,
"currency": "USD"
}
},
{// new object I want to insert into
"category": {
"coding": [
{
"system": "sys_denail",
"code": "denialreason"
}
],
"reason": {
"coding": [
{
"system": "https://example.com",
"code": "A1"
}
],
"text": "unknown"
}}
}
]
}
],
"payment": {
"type": {
"coding": [
{
"system": "http://payment.com",
"code": "denied" //change the value to denied
}
],
"text": "denied" //change the value to denied
}
}
}
Edit : I've tried to answer the second case by myself to be evaluated after the first case is answered
Welcome to SO, please ask minimal and reproducible questions, and show your effort tried for the future.
What you need is to use a conditional logic along with placeholder values with ampersand symbols depending on the levels of each key name within the tree.
I have partially answered, which will handle the bottom part of your question. Indeed the logic for the rest(inserting an object to the array will be similiar)
So, consider having a look at the following solution
[
{
"operation": "shift",
"spec": {
"*": "&",
"payment": {
"type": {
"coding": {
"*": {
"*": "&4.&3.&2[&1].&",
"code": {
"paid": {
"#1": "&6.&5.&4[&3].&2",
"#(4,text)": "&6.text"
},
"*": {
"#denied": "&6.&5.&4[&3].code",
"#(4,text)": {
"#denied": "&6.text"
}
}
}
}
}
}
}
}
}
]
Edit(for your own answer related to adding an object):
your current idea of using shift after default transformation spec is pretty good, you can rephrase like
[
{
"operation": "default",
"spec": {
"temp_deny": {
"denialreason": {
"category": {
"coding": [
{
"system": "sys_denail",
"code": "denialreason"
}
],
"reason": {
"coding": [
{
"system": "https://example.com",
"code": "A1"
}
],
"text": "unknown"
}
}
}
}
}
},
{
"operation": "shift",
"spec": {
"*": "&",
"item": {
"*": {
"*": "&2[&1].&",
"ADJ": {
"#": "&3[&2].&",
"#(4,temp_deny)": "&3[&2].&"
}
}
}
}
}
]

How to exclude specific fields from JSON using groovy

I would like to exclude the items which don't have productModel property in the below JSON. How can we achieve this in groovy
I tried using hasProperty but not worked for me as expected. If possible can I get some sample snippet
I tried below code - but didn't work as I expected.
response.getAt('myData').getAt('data').getAt('product').hasProperty('productModel').each { println "result ${it}" }
Any help would be really appreciated.
{
"myData": [{
"data": {
"product": {
"productId": "apple",
"productName": "iPhone",
"productModel": "6s"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {}
},
{
"data": {
"product": {
"productId": "apple",
"productName": "iPhone",
"productModel": "7"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {}
},
{
"data": {
"product": {
"productId": "apple",
"productName": "Macbook"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {}
}
],
"metadata": {
"count": 3,
"offset": 0
}
}
If you want to exclude specific fields from JSON object then you have to recreate it using filtered data. The crucial part takes these two lines (assuming that json variable in the below example stores your JSON as text):
def root = new JsonSlurper().parseText(json)
def myData = root.myData.findAll { it.data.product.containsKey('productModel') }
What happens here is we access root.myData list and we filter it using findAll(predicate) method and predicate in this case says that only objects that have key productModel in path data.product are accepted. This findAll() method does not mutate existing list and that is why we store the result in variable myData - after running this method we will end up with a list of size 2.
In next step you have to recreate the object you want to represent as a JSON:
def newJsonObject = [
myData: myData,
metadata: [
count: myData.size(),
offset: 0
]
]
println JsonOutput.prettyPrint(JsonOutput.toJson(newJsonObject))
In this part we create newJsonObject and in the end we convert it to a JSON representation.
Here is the full example:
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
def json = '''{
"myData": [{
"data": {
"product": {
"productId": "apple",
"productName": "iPhone",
"productModel": "6s"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {}
},
{
"data": {
"product": {
"productId": "apple",
"productName": "iPhone",
"productModel": "7"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {}
},
{
"data": {
"product": {
"productId": "apple",
"productName": "Macbook"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {}
}
],
"metadata": {
"count": 3,
"offset": 0
}
}'''
def root = new JsonSlurper().parseText(json)
def myData = root.myData.findAll { it.data.product.containsKey('productModel') }
def newJsonObject = [
myData: myData,
metadata: [
count: myData.size(),
offset: 0
]
]
println JsonOutput.prettyPrint(JsonOutput.toJson(newJsonObject))
And here is the output it produces:
{
"myData": [
{
"data": {
"product": {
"productId": "apple",
"productName": "iPhone",
"productModel": "6s"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [
{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {
}
},
{
"data": {
"product": {
"productId": "apple",
"productName": "iPhone",
"productModel": "7"
},
"statusCode": "active",
"date": "2018-08-07T00:00:00.000Z"
},
"links": [
{
"productUrl": "test"
},
{
"productImage": "test"
}
],
"info": {
}
}
],
"metadata": {
"count": 2,
"offset": 0
}
}

Stellar cross currency transaction doesn't work

I'm unable to execute payment transaction in Stellar testnet.
Initially i use find_path:
curl -X POST https://test.stellar.org:9002 -d '
{
"method": "static_path_find",
"params": [
{
"source_account": "g4e5v2ERpKvdBZrchn6DrWUtvezkXsu5wo",
"destination_account": "gJ3e65GzqERgeeS5oXsv8NGfdZWzm93ej6",
"source_currencies" : [ { "currency" : "SGD", "issuer" : "gDfapfG5hDHuYkbVpugtupkGYVTKXwd59r"} ],
"destination_amount": {
"currency": "MYR",
"value": "1",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS"
}
}
]
}'
The result I get:
{
"result": {
"alternatives": [
{
"paths_computed": [
[
{
"currency": "MYR",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 48
},
{
"account": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 1
}
]
],
"source_amount": {
"currency": "SGD",
"issuer": "gDfapfG5hDHuYkbVpugtupkGYVTKXwd59r",
"value": "0.375"
}
}
],
"destination_account": "gJ3e65GzqERgeeS5oXsv8NGfdZWzm93ej6",
"destination_currencies": [
"MYR",
"STR"
],
"status": "success"
}
}
Then I trying to broadcast transaction in the network:
curl -X POST https://test.stellar.org:9002 -d '
{
"method": "submit",
"params": [
{
"secret": "sfk7dUd4N8cxVFVowsZL4DQgonNP9k8WFBgaV2NmwEQKGzWuqXT",
"tx_json": {
"TransactionType": "Payment",
"Account": "g4e5v2ERpKvdBZrchn6DrWUtvezkXsu5wo",
"Destination": "gJ3e65GzqERgeeS5oXsv8NGfdZWzm93ej6",
"Amount": {
"currency": "MYR",
"value": "1",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS"
},
"Paths": [
[
{
"currency": "MYR",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 48
},
{
"account": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 1
}
]
]
}
}
]
}'
And finally I'm getting unsuccessful result when transaction passed through consensus:
{
"engine_result": "tecPATH_PARTIAL",
"engine_result_code": 101,
"engine_result_message": "Path could not send full amount.",
"ledger_hash": "82BCF42941EF00BEA9E575B696CD88EC7E14FDE8CFD39FDA6A76B5710FDD0755",
"ledger_index": 704612,
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "g4e5v2ERpKvdBZrchn6DrWUtvezkXsu5wo",
"Balance": "199999960",
"Flags": 0,
"OwnerCount": 1,
"Sequence": 5
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "D3433DEE556200D8AB72DED7156A597A273103D2BC50F526193EB9C4D8C8B735",
"PreviousFields": {
"Balance": "199999970",
"Sequence": 4
},
"PreviousTxnID": "6ADF48B45D95B3ABD20FD78F95F7E4F20D91FF5D169ECC5EFD6DB0CA78BEA486",
"PreviousTxnLgrSeq": 704445
}
}
],
"TransactionIndex": 0,
"TransactionResult": "tecPATH_PARTIAL"
},
"status": "closed",
"transaction": {
"Account": "g4e5v2ERpKvdBZrchn6DrWUtvezkXsu5wo",
"Amount": {
"currency": "MYR",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"value": "1"
},
"Destination": "gJ3e65GzqERgeeS5oXsv8NGfdZWzm93ej6",
"Fee": "10",
"Flags": 2147483648,
"Paths": [
[
{
"currency": "MYR",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 48
},
{
"account": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 1
}
]
],
"Sequence": 4,
"SigningPubKey": "4B640AC0C64AEF1C97EAAD0629CADDCA95FBA5F095BD20BD6282BEC450A125B1",
"TransactionType": "Payment",
"TxnSignature": "7BF5772EB916F20F56C5F148E99C3C3DD77C2916EAA47AB2D7FA8306F2B4A9D3FA4B789BDB79899A634B0C33F50A6ACB447CA6A9633C1C73BAB754FBFE74C105",
"date": 485412700,
"hash": "846AB6502D3B7A3137B2B538E6616B9C4459D2A67C48E58AF6B64F4659FF0016"
},
"type": "transaction",
"validated": true
}
Why? What I did wrong? I really can't understand...
Anyway I found the problem.
I forgot to add required SendMax parameter when submitting transaction.
curl -X POST https://test.stellar.org:9002 -d '
{
"method": "submit",
"params": [
{
"secret": "sfk7dUd4N8cxVFVowsZL4DQgonNP9k8WFBgaV2NmwEQKGzWuqXT",
"tx_json": {
"TransactionType": "Payment",
"Account": "g4e5v2ERpKvdBZrchn6DrWUtvezkXsu5wo",
"Destination": "gJ3e65GzqERgeeS5oXsv8NGfdZWzm93ej6",
"Amount": {
"currency": "MYR",
"value": "1",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS"
},
"Paths": [
[
{
"currency": "MYR",
"issuer": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 48
},
{
"account": "gsQuUKcxM68nEX9tKR71UH5hZXwrvT2mpS",
"type": 1
}
]
],
"SendMax" : { "currency" : "SGD", "value" : "0.375", "issuer": "gDfapfG5hDHuYkbVpugtupkGYVTKXwd59r" }
}
}
]
}'