I am struggling in this dataweave language [duplicate] - mule

This question already has answers here:
dataweave transformation
(3 answers)
Closed 4 months ago.
Input :
{
"payload": {
"Field_X": "X",
"Field_Y": 10,
"Field_Z": "Z",
"Field_W" : {
"sub_1": "value_1",
"sub_2": true,
"sub_3": "value_3"
}
},
"mapper": {
"A": "<payload.Field_X>",
"B": "<payload.Field_Y>",
"C": "Fields or text not mapped to payload",
"D": {
"subD_1": "<payload.Field_W.sub_2>",
"subD_2": "<payload.Field_W.sub_4>"
}
}
}
Output
{
"A": "X",
"B": 10,
"C": "Fields or text not mapped to payload",
"D": {
"subD_1": true,
"subD_2": null
}
}
Note: Pls note that hardcoding is not allowed as per the client's request.
Every key-value pair has to be looped.

Based on my understanding of the original question, the following DataWeave script should accomplish the goal. I broke out the work into multiple functions so that it would be easier to follow.
%dw 2.4
output application/json
fun isExpression(value: String): Boolean = ((value startsWith("<")) and (value endsWith(">")))
fun extractExpression(value: String): Any = do {
if (isExpression(value))
dw::core::Strings::unwrap(value, "")
else value
}
fun evaluatePath(context: Object, expression: String): Any = do {
var tokens = expression splitBy "."
---
tokens reduce (val, acc = context) -> acc[val]
}
fun retrieveMappedValue(context: Object, value: String): Any = do {
var retValue = if (isExpression(value))
evaluatePath(context, extractExpression(value))
else value
---
retValue
}
fun remap(context: Object, object: Any, fn): Any = do {
if (object is Object)
entriesOf(object) reduce (val, acc = {}) -> dw::core::Objects::mergeWith(acc, {
(val.key): remap(context, val.value, fn)
})
else fn(context, object)
}
---
remap(payload, payload.mapper, retrieveMappedValue)

Related

Looking for the simplest way to unwrap root element for certain responses with FeignClient

I have a FeignClient which communicates with an external service, looks like below:
interface JiraClient {
\\ ...
#RequestMapping(method = [RequestMethod.GET], value = ["\${jira.api.agile}/sprint/{sprintId}/issue"])
fun getIssuesForASprint(
#PathVariable("sprintId") sprintId: Int,
#RequestParam(name = "startAt", required = false) startAt: Int = 0,
#RequestParam(name = "maxResults", required = false) maxResults: Int = MAX_RESULTS
): IssueHolder
#RequestMapping(method = [RequestMethod.GET], value = ["\${jira.api.insight}/objectschema/list"])
fun getObjectSchemaList(): List<ObjectSchema>
}
And here is my POJO:
#JsonIgnoreProperties(ignoreUnknown = true)
data class ObjectSchema(
#JsonProperty("id") val id: Int,
#JsonProperty("name") val name: String?,
#JsonProperty("objectSchemaKey") val objectSchemaKey: String?,
#JsonProperty("status") val status: String?,
#JsonProperty("created") #JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
) val created: Date?,
#JsonProperty("updated") #JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
) val updated: Date?,
#JsonProperty("objectCount") val objectCount: Int?,
#JsonProperty("objectTypeCount") val objectTypeCount: Int?
)
It won't work because the response has an additional root element:
{
"objectschemas": [
{
"id": 1,
"name": "APPS CATALOG",
"objectSchemaKey": "AC",
"status": "Ok",
"created": "2020-01-01T11:11:11.000Z",
"updated": "2020-01-01T11:11:11.000Z",
"objectCount": 123,
"objectTypeCount": 10
},
{
"id": 2,
"name": "ORG CATALOG",
"objectSchemaKey": "OC",
"status": "Ok",
"created": "2020-01-01T11:11:11.000Z",
"updated": "2020-01-01T11:11:11.000Z",
"objectCount": 456,
"objectTypeCount": 20
}
]
}
For the other responses, I have created holder data classes, because they have pagination info, that makes sense:
{
"expand": "schema,names",
"startAt": 0,
"maxResults": 200,
"total": 1024,
"issues": [
...
]
}
Goal:
I'd like to get it work, with an easy way to add some annotations (e.g.: # JsonRootName ) to certain data classes (but not all), so that I can unwrap the root value objectschemas out of the box. Please note, that the data class used here is only for deserialization purpose, I will not need it for serialization. And I don't wanna add a bunch of logic into fun feignDecoder(): Decoder. For the Feign Client interface, there is no chance to add any logic like DeserializationFeature.UNWRAP_ROOT_VALUE.
Does anyone know the easiest way to achieve this? Thank you very much.
The complete code snippets can be found here.

How to make GroupBy result list to new Map in Webflux

How to make GroupBy result list to new Map in Webflux
There is my input list and expect result. then what should I do to make the result.
// expect
{
"timestamp": "2019-06-13T00:00:00.000",
"result": {
"first": 1,
"second": 2,
"third": 3
}
}
// input list
[
{
"timestamp": "2019-06-13T00:00:00.000",
"first": 1
},
{
"timestamp": "2019-06-13T00:00:00.000",
"second": 2
},
{
"timestamp": "2019-06-13T00:00:00.000",
"third": 3
}
]
val Flux.fromIterable(list)
.groupBy{it.timestamp}
.concatMap { groupItem ->
// here!! I want to make `group by result list to new Map``
Result(timestamp = groupItem.key()!!, Item(first = ?, second = ?, third =?))
}
I figured it out.
Flux.merge(first, second, thrid)
.groupBy { it.timestamp }
.concatMap {
it.map { item ->
val container = mutableMapOf<String, Any>()
if (item is firstEntity) {
container["first"] = item.result.count
container["timestamp"] = it.key()!!
}
if (item is secondEntity) container["second"] = item.result.count
if (item is thridEntity) container["thrid"] = item.result.count
container
}.reduce { acc, current ->
acc.putAll(current)
acc
}
}
.map {
val first = (it["first"] ?: 0) as Int
val second = (it["second"] ?: 0) as Int
val thrid = (it["thrid"] ?: 0) as Int
val timestamp = (it["timestamp"] ?: "") as String
// somthing!!
}

How to build a multiple IF conditional in Mule 4 and DW 2.0?

I need to create a function with conditions like this pseudo-code:
var consent = []
function buildConsent() {
if (condition1) {
consent += values1
}
if (condition2) {
consent += values2
}
if (condition3) {
consent += values3
}
}
This is how I am doing it on Mule4 and DW 2.0:
%dw 2.0
var consent = []
var factIntake = vars.facts
fun buildConsent() =
if (factIntake.miscFactItems[?($.value1 == true)] != null) {
consent + {
"Consent_Type": "some1",
"Consent_Given_By": "some2"
}
}
if (factIntake.miscFactItems[?($.value2 == true)] != null) {
consent + {
"Consent_Type": "some3",
"Consent_Given_By": "some4"
}
}
output application/json
--
{
"Consent_Data": buildConsent()
}
But I am getting the following error from the IDE (AnypointStudio 7):
Invalid input '+', expected Namespace or
Attribute<'#('(Name:Value)+')'> (line 11, column 11):
Where line 11, column 11 is the first appearance of consent +. If I try to debug the project all I got in the console is:
Message : Error while parsing script: %dw 2.0
Here is an example of input/output for you to better understand what I am trying to achieve:
// Input
{
"miscFactItems": [{
"factId": "designeeFirstName",
"factValue": "test test",
"factValueType": "System.String"
}, {
"factId": "designeeLastName",
"factValue": "test test",
"factValueType": "System.String"
},{
"factId": "value1",
"factValue": true,
"factValueType": "System.Boolean"
}, {
"factId": "value2",
"factValue": true,
"factValueType": "System.Boolean"
}, {
"factId": "value3",
"factValue": true,
"factValueType": "System.Boolean"
}
]
}
// Output
consent = [{
"Consent_Type": "type1",
"Consent_Given_By": miscFactItems.designeeFirstName
}, {
"Consent_Type": "type2",
"Consent_Given_By": miscFactItems.designeeFirstName
}, {
"Consent_Type": "type3",
"Consent_Given_By": miscFactItems.designeeFirstName
}
]
What I am missing here? How do I add the three conditions to my function and append the values to the consent var?
In DataWeave variables are immutable, so you can't accumulate things in the same variable, you need to create new variables.
So it would look something like this:
%dw 2.0
output application/json
var consent1 = if (condition1) [{"Consent_Type": "some1", "Consent_Given_By": "some2"}] else []
var consent2 = if (condition2) [{"Consent_Type": "some3", "Consent_Given_By": "some4"}] else []
---
consent1 ++ consent2
Your requirement looks like a good use of reduce function. Based on the pseudo code you provided, you can do something like below
output application/json
var payload = [
{"name":"Ram", "email":"Ram#gmail.com", "state": "CA","age":21},
{"name":"Bob", "email":"bob32#gmail.com","state": "CA","age":30},
{"name":"john", "email":"bob32#gmail.com","state": "NY","age":43}
]
---
payload reduce ((item, consent = []) -> consent +
{
(state: item.state) if(item.state=='CA'),
(age: item.age) if(item.age >25)
}
)

get array from inside many objects in kotlin

l am try to build simple app provide flight schedule . the problem is l have many object in json url and the array list inside of these object and l cant to get array list from objects because l got error fatal Caused by: org.json.JSONException: Value
my data json api
{
"result": {
"response": {
"airport": {
"pluginData": {
"schedule": {
"arrivals": {
"data": [
{
"flight": {
"identification": {
"id": null,
"row": 4832637003,
"number": {
"default": "ZP4801",
"alternative": null
},
"callsign": null,
"codeshare": null
}
}
}
]
}
}
}
}
}
}
}
my code for getting data json of array list
private fun handleJson (jsonString: String?){
val jsonArray = JSONArray(jsonString)
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()){
val jsonObject = jsonArray.getJSONObject(x)
list.add(FlightShdu(
jsonObject.getInt("id"),
jsonObject.getString("callsign")
))
x++
}
val adapter = ListAdapte(this#MainActivity,list)
flightShdu_list.adapter = adapter
}
I would normally suggest for a full structure of the JSON via data classes, as this methodology could potentially be expensive to run multiple times over and over... The following highlights a method to dig into the JSON through jsonObjects by name, and then take the final layer of "identification" and populates a data class that is serializable with the resulting object
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.json.JsonDecodingException
import kotlinx.serialization.json.JsonElement
val data =
"""
{
"result": {
"response": {
"airport": {
"pluginData": {
"schedule": {
"arrivals": {
"data": [{
"flight": {
"identification": {
"id": null,
"row": 4832637003,
"number": {
"default": "ZP4801",
"alternative": null
},
"callsign": null,
"codeshare": null
}
}
}]
}
}
}
}
}
}
}
"""
#Serializable
data class FlightIdentification(
val id: Int?,
val row: String,
val number: IdentificationNumber,
val callsign: String?,
val codeshare: String?
) {
#Serializable
data class IdentificationNumber(
val default: String,
val alternative: String?
)
}
val json = Json(JsonConfiguration.Stable)
fun JsonElement?.get(name: String): JsonElement? {
return if (this == null) null
else this.jsonObject[name]
}
fun handleJson(jsonString: String) {
val obj = json.parseJson(jsonString)
val data = obj.get("result").get("response").get("airport").get("pluginData")
.get("schedule").get("arrivals").get("data")
if (data != null) {
val flight = data.jsonArray[0]
.get("flight").get("identification")
try {
val res = json.parse(FlightIdentification.serializer(), flight.toString())
println(res)
} catch (e: JsonDecodingException) {
println("Decode: ${e.message}")
}
}
}
handleJson(data)

How to read a subsection from a firebase database

I am using this code to access a Firebase Database, but I am cannot figure out how to read the sub array of strings. (the JSON structure is below)). The code I have returns the top level items, but not the list of strings. Would someone be able to assist with this issue?
Here is my function to read from the DB:
func sizes(userId: String = Auth.auth().currentUser!.uid, success: #escaping ([Sizes]) -> ()) {
let ref = Router.sizes.reference()
let query = ref.queryOrdered(byChild: "name") //userId)
query.observe(.value, with: { snapshot in
var array = [Sizes]()
for child in snapshot.children {
if let size = Mapper<Sizes>().map(JSON: (child as! DataSnapshot).value as! [String : AnyObject]) {
array.append(size)
}
}
success(array)
})
}
My Firebase JSON is as follows:
{
"-SzCat_001": {
"name": "Womans",
"sizeCategories": {
"name": "Pants",
"sizeDescriptor": [
"00",
"0",
"2",
"4",
"6",
"8",
"10",
"12",
"XL"
]
}
}
}
And this is what I get returned?
[0] = {
name = "Womans"
sizeCategories = 0 values {} }
I am trying to figure out how to read the sizeCategories list of strings as a subarray of sizes.
Here is my definition of sizes and sizeCategories:
struct Sizes: Mappable {
var name: String = ""
var sizeCategories = [SizeCategories]()
init() {
}
init?(map: Map) {
}
mutating func mapping(map: Map) {
name <- map["name"]
sizeCategories <- map["sizeCategories"]
}
}
struct SizeCategories: Mappable {
var name: String = ""
var sizeDescriptor = [String]()
init() {
}
init?(map: Map) {
}
mutating func mapping(map: Map) {
name <- map["name"]
sizeDescriptor <- map["sizeDescriptor"]
}
}
Thanks for any help!!!
You're jumping through a lot of hoops to read the data here. You could just let allMyData = snapshot.value as! [String: AnyObject] and know that each internal value is also a [String: AnyObject]. But if you really want to destructure into something more typed with this mapping technique, have a look at your sizes definition:
var sizeCategories = [SizeCategories]()
This says "sizeCategories is an array of SizeCategories type". But your data is not structured as an array, it is a dict:
"sizeCategories": {
"name": "Pants",
"sizeDescriptor": [
"00",
"0",
"2",
"4",
"6",
"8",
"10",
"12",
"XL"
]
}
You need to adjust your definition and mapping method here for this field.