loop inside transform in mule - mule

i am new to mule and i have to convert json to xml.here is the transform output code
%dw 1.0
%input payload application/json
%output application/xml
---
{(
items:
{
Id:payload.abc.productid,
ProductPrice:payload.abc.price,
Name:payload.abc.productname
}
)}
Here is the schema against which i am testing
{
"abc":
{
"productid":"4",
"productname":"Shampoo",
"price":["1000","2000","3000"]
}
}
It generates correct xml in case i send only one item in array price but in case i send multiple elements it gives me this error
Cannot coerce a :array to a :object.
I know i should loop inside it but i do not know how to make it possible
Please guide!

You could use the following:
{
items: {
(payload map ((payload01 , indexOfPayload01) -> {
item: {
Id: payload01.productid,
Name: payload01.productname,
(payload01.price map ((price , indexOfPrice) -> {
price: price
}))
}
}))
}
}
I have removed the "abc" from the incoming data so the format is as:
[
{
"productid":"4",
"productname":"Shampoo",
"price":["1000","2000","3000"]
},
{
"productid":"4",
"productname":"not shampoo",
"price":["1000","2000","3000"]
}
]
Let me know if the abc needs to be there, but I hope this helps

you can use the map keyword to iterate over arrays in Dataweave. Take a look at the documentation here.

Related

Use variable for json answer in QML BlackBerry

I have a project in QML, MomenticsID (BlackBerry10).
I need to use the variable for json answer.
I can not find some manual for this problem.
When I use var result = data.item_01[0] everything is OK and program results in correct value.
But when I use var result = data.variable I won't get an answer.
main.qml
import bb.cascades 1.4
import bb.data 1.0
Page {
id: page
property string variable: "item_01[0]"
Container {
Label {
id: label
}
}
attachedObjects: [
DataSource {
id: dataSource
type: DataSourceType.Json
source: "asset:///data.json"
onDataLoaded: {
var result = data.item_01[0] // it's OK, result is "a"
//var result = data.variable // it's NOK, nothing result
label.text = result.answer_01
}
}
]
onCreationCompleted: {
dataSource.load()
}
}
data.json
{
"item_01": [
{
"answer_01": "a"
}
]
}

I have a json =

I have input json
[
{
"nm": "BRANCHID",
"vl": "1"
},
{
"nm": "TELLERID",
"vl": "9903"
},
{
"nm": "mobile",
"vl": "9903234565"
}
]
I need to check nm equal to BRANCHID or TELLERID then would set V1 value accordingly and output:
{"BRANCHID":"1"},
{"TELLERID",:"9903"}
Filter by the items you need and then construct a new object combining the nm and vl attributes:
%dw 2.0
output application/json
---
payload
filter ((item) -> item.nm == 'BRANCHID' or item.nm == "TELLERID")
map ((item) -> {(item.nm) : item.vl})
Sort the data into a new object. There's probably a more sophisticated way to do this, but this should work.
let newObj = {};
json.forEach(sort);
function sort(item, index){
newObj[ json[index].nm ] = json[index].vl;
}
https://jsfiddle.net/r75haec8/

Add a new element in each array of objects where array may have different length in mongodb

I have a following shema.
{
id:week
output:{
headerValues:[
{startDate:"0707",headers:"ID|week"},
{startDate:"0715",headers:"ID1|week1"},
{startDate:"0722",headers:"ID2|week2"}
]
}
}
I have to add a new field into headerValues array like this:
{
id:week
output:{
headerValues[
{startDate:"0707",headers:"ID|week",types:"used"},
{startDate:"0715",headers:"ID1|week1",types:"used"},
{startDate:"0722",headers:"ID2|week2",types:"used"}
]
}
}
I tried different approaches like this:
1)
db.CollectionName.find({}).forEach(function(data){
for(var i=0;i<data.output.headerValues.length;i++) {
db.CollectionName.update({
"_id": data._id, "output.headerValues.startDate":data.output.headerValues[i].startDate
},
{
"$set": {
"output.headerValues.$.types":"used"
}
},true,true
);
}
})
So, In this approach it is executing script and then failing. It is updating result with failed statement.
2)
Another approach I have followed using this link:
https://jira.mongodb.org/browse/SERVER-1243
db.collectionName.update({"_id":"week"},
{ "$set": { "output.headerValues.$[].types":"used" }
})
But it fails with error:
cannot use the part (headerValues of output.headerValues.$[].types) to
traverse the element ({headerValues: [ { startDate: "0707", headers:
"Id|week" } ]}) WriteError#src/mongo/shell/bulk_api.js:469:48
Bulk/mergeBatchResults#src/mongo/shell/bulk_api.js:836:49
Bulk/executeBatch#src/mongo/shell/bulk_api.js:906:13
Bulk/this.execute#src/mongo/shell/bulk_api.js:1150:21
DBCollection.prototype.updateOne#src/mongo/shell/crud_api.js:550:17
#(shell):1:1
I have searched with many different ways which can update different arrays object by adding new field to each object but no success. Can anybody please suggest that what am I doing wrong?
Your query is {"_id" : "week"} but in your data id field is week
So you can change {"_id" : "week"} to {"id" : "week"} and also update your mongodb latest version
db.collectionName.update({"id":"week"},
{ "$set": { "output.headerValues.$[].types":"used" }
})

Inline transform specific attributes in JSON payload containing nested arrays and objects of key/value pairs

I have an input payload that I need to pass through directly to the output except for specific date attributes which I need to transform. These date attributes can be anywhere within the payload. i.e.,
as key/value pairs
as key/value pairs within an object
as key/value pairs within an array
as key/value pairs within an object in an array
I have addressed cases 1 and 2 above with the dataweave code below. However, I am a little stuck with cases 3 and 4. Would very much appreciate any pointers in this regard. Thanks!
Input payload:
{
"key1":"value1",
"key2":"value2",
"arrayList1":[
{
"key3":"value3",
"datefield_1":"13/01/2006",
"datefield_2":"15/06/1980",
"arrayList2":[
{
"key4":"value4",
"datefield_3":"13/01/2000",
"datefield_4":"15/06/2003",
"arrayList2":[
{
"key5":"value5",
"datefield_5":"30/01/2000",
"datefield_6":"14/06/2003"
}
]
}
]
},
{
"key6":"value6",
"datefield_7":"20/02/2000"
}
]
}
Dataweave code:
%dw 1.0
%output application/json
%var keysToUpdate = ['datefield_1', 'datefield_2', 'datefield_3', 'datefield_4', 'datefield_5', 'datefield_6', 'datefield_7']
%function transformDateFormat(inputDate) inputDate as :date {format: "dd/MM/yyyy"} as :date {format: "yyyy-MM-dd"}
%function findKey(key) keysToUpdate contains key
%function changePayload(input) input mapObject ({
($$): changePayload($) when $ is :object otherwise $
} unless findKey($$ as :string) otherwise {
($$): transformDateFormat($)
})
---
changePayload (payload)
The match operator with some recursion will be helpful here.
Try this out. I created a function, applyToValuesWhenKey, that takes in the input value as e, a function to apply to the values as fn, and a function that returns a boolean that will dictate whether or not to apply fn to the value called predicate. It uses recursion and the match operator to loop through the data, applying map, mapObject, or just returning the given value depending on whether or not the current value is an object, array, or anything else. The rest is your code:
%dw 1.0
%output application/json
%var input = {
"key1":"value1",
"key2":"value2",
"arrayList1":[
{
"key3":"value3",
"datefield_1":"13/01/2006",
"datefield_2":"15/06/1980",
"arrayList2":[
{
"key4":"value4",
"datefield_3":"13/01/2000",
"datefield_4":"15/06/2003",
"arrayList2":[
{
"key5":"value5",
"datefield_5":"30/01/2000",
"datefield_6":"14/06/2003"
}
]
}
]
},
{
"key6":"value6",
"datefield_7":"20/02/2000"
}
]
}
%var keysToUpdate = [ 'datefield_1', 'datefield_2', 'datefield_3', 'datefield_4', 'datefield_5', 'datefield_6', 'datefield_7' ]
%function applyToValuesWhenKey( e, fn, predicate )
e match {
:array -> $ map applyToValuesWhenKey( $, fn, predicate ),
:object -> $ mapObject ( ( v, k ) -> {
( k ): fn( v )
} when predicate( k ) otherwise {
( k ): applyToValuesWhenKey( v, fn, predicate )
}
),
default -> $
}
%function transformDateFormat( date )
date as :date { format: "dd/MM/yyyy" } as :date { format: "yyyy-MM-dd" }
%function transformDates( input )
applyToValuesWhenKey( input,
transformDateFormat,
( ( key ) -> keysToUpdate contains ( key as :string ) ) )
---
transformDates( input )

Invocation from function in QML?

I can share an item easily using an InvokeActionItem in a Page but I need to be able to call it in a listview item. I've managed to trigger an invoke, but I cannot figure out how to add data when triggering it. I keep getting an error message of
InvocationPrivate::setQuery: you are not allowed to change InvokeQuery object
Note: I am trying to do this in purely QML, I will do it via c++ if necessary but QML would be preferable.
Code that works inside a Page object:
actions: [
InvokeActionItem {
ActionBar.placement: ActionBarPlacement.OnBar
title: "Share"
query {
mimeType: "text/plain"
invokeActionId: "bb.action.SHARE"
}
onTriggered: {
//myTextProperty is a string variable property for the page.
data = myTextProperty;
}
}
]
The code I've tried to use in the other item is as follows, but does NOT work:
Container {
gestureHandlers: [
TapHandler {
LongPressHandler {
onLongPressed: {
console.log("Longpress");
invokeQuery.setData("test");
invokeShare.trigger("bb.action.SHARE");
}
}
]
attachedObjects: [
Invocation {
id: invokeShare
query: InvokeQuery {
id:invokeQuery
mimeType: "text/plain"
}
}
]
}
Is there a way to change the data for an invoke purely with QML or do I need to just run it through c++ instead?
After a fair amount of browsing forums and testing various methods, I have finally found one that works.
Add the following in your attachedObjects:
attachedObjects: [
Invocation {
id: invokeShare
query: InvokeQuery {
id:invokeQuery
mimeType: "text/plain"
}
onArmed: {
if (invokeQuery.data != "") {
trigger("bb.action.SHARE");
}
}
}
]
Then wherever you need to call the invocation do the following:
invokeQuery.mimeType = "text/plain"
invokeQuery.data = "mytext";
invokeQuery.updateQuery();
Note that if you do not do a check in the onArmed for data it will automatically call the invocation on creation - in the case of a listview this can result in 20+ screens asking you to share on bbm... ;)
You can actually use the InvokeActionItem, you just have to call updateQuery to retrigger the invokeQuery.
When the ListItemData changes, the binding will cause the values to update.
InvokeActionItem {
enabled: recordItem.ListItem.data.videoId != undefined
id: invokeAction
query{
uri: "http://www.youtube.com/watch?v=" + recordItem.ListItem.data.videoId
onQueryChanged: {
updateQuery()
}
}
}
For remove "InvocationPrivate::setQuery: you are not allowed to change InvokeQuery object" message I use this:
attachedObjects: [
Invocation {
id: invoke
query {
mimeType: "text/plain"
invokeTargetId: "sys.bbm.sharehandler"
onDataChanged: {
console.log("change data")
}
}
onArmed: {
if (invoke.query.data != "") {
invoke.trigger("bb.action.SHARE");
}
}
}
]
function shareBBM(){
invoke.query.setData("TEXT TO SHARE");
invoke.query.updateQuery();
}