How to Check null condition in Data weaver : Mule - mule

Here is my xml, in that first I need to check 'RecordsEntries' should not be 'null', then RecordEntry shouldn't be null followed by mapping code
<?xml version="1.0" encoding="UTF-8"?>
<Records>
<storenumber />
<calculated>false</calculated>
<subTotal>12</subTotal>
<RecordsEntries>
<RecordEntry>
<deliverycharge>30.0</deliverycharge>
<entryNumber>8</entryNumber>
<Value>true</Value>
</RecordEntry>
<RecordEntry>
<deliverycharge>20.0</deliverycharge>
<entryNumber>7</entryNumber>
<Value>false</Value>
</RecordEntry>
</RecordsEntries>
<RecordsEntries>
<RecordEntry>
<deliverycharge>30.0</deliverycharge>
<entryNumber>8</entryNumber>
<Value>false</Value>
</RecordEntry>
</RecordsEntries>
</Records>
Tried multiple scenario's also used when condition checking but somewhere missing parenthesis or correct format
orders: {
order: {
StoreID: payload.Records.storenumber,
Total: payload.Records.calculated,
(( payload.Records.RecordsEntries.*RecordEntry ) map {
IndividualEntry: {
Number:$.entryNumber,
DeliverCharge:$.deliverycharge
}
} when ( payload.Records.RecordsEntries != null and payload.Records.RecordsEntries.*RecordEntry !=null))}
}
getting error like missing ). Tried other way around by checking the null condition directly inside the first loop got error like "Cannot coerce array to an boolean". Please suggest. Thanks.

You can instead do
%dw 1.0
%output application/xml
---
orders: {
order: {
StoreID: payload.Records.storenumber,
Total: payload.calculated,
((payload.Records.*RecordsEntries.*RecordEntry default []) map {
IndividualEntry: {
Number:$.entryNumber,
DeliverCharge:$.deliverycharge
}
})
}
}
DataWeave is "null-safe" for querying values like in payload.Records.*RecordsEntries.*RecordEntry, but an error will be thrown when trying to operate with a null (e.g. null map {}).
The default operator replaces the value to its left, if it's null, with the one on the right.
Also you were missing an *. You need to use it in xml whenever you want all the repetitive elements that match.

If you want to skip a particular field assignment in dataweave based on the null or blank , below mentioned script can be used.
payload map ((payload01 , indexOfPayload01) -> { Name: payload01.Name, (LastName: payload01.LastName) when payload01.LastName !=null and payload01.LastName !='' })
This will skip the field mapping for Name , if the name field is coming as null or blank in the incoming payload.

Related

How to identify if one json contains specific value in json schema

There is a json result like this below, and I need to check if a specific value is contained in shop_ids, for example, 232323 is contained, while 232324 is not. Is it possible to achieve that with JSON Schema? How?
{
"request":{
"0":{
"cids":{
"0":"a",
"1":"b",
"2":"c",
"3":"d",
"4":"e",
"5":"f",
"6":"g",
"7":"h"
},
"data_type":"1",
"key_type":"1",
"one_item_id":"0",
"queries":{
"0":{
"0":"query1"
},
"1":{
"0":"query2"
}
},
"shop_ids":{
"0":"11111",
"1":"232323",
"2":"33333",
"3":"124151",
"4":"55555",
"5":"12121"
},
"num":"30"
}
}
}
note: the shop_ids may contain more numeric fields, not just 0-5.
I tried "patternProperties", it does work for checking specific key-value but returns fail on other key-value. What I need is just any of "shop_ids" match the specific value is ok.

Oracle SQL JSON_QUERY ignore key field

I have a json with several keys being a number instead of a fixed string. Is there any way I could bypass them in order to access the nested values?
{
"55568509":{
"registers":{
"001":{
"isPlausible":false,
"deviceNumber":"55501223",
"register":"001",
"readingValue":"5295",
"readingDate":"2021-02-25T00:00:00.000Z"
}
}
}
}
My expected output here would be 5295, but since 59668509 can vary from json to json, JSON_QUERY(data, '$."59668509".registers."001".readingValue) would not be an option. I'm not able to use regexp here because this is only a part of the original json, which contains more than this.
UPDATE: full json with multiple occurrences:
This is how my whole json looks like. I would like all the readingValue in brackets, in the example below, my expected output would be [32641, 00964].
WITH test_table ( data ) AS (
SELECT
'{
"session":{
"sessionStartDate":"2021-02-26T12:03:34+0000",
"interactionDate":"2021-02-26T12:04:19+0000",
"sapGuid":"369F01DFXXXXXXXXXX8553F40CE282B3",
"agentId":"USER001",
"channel":"XXX",
"bpNumber":"5551231234",
"contractAccountNumber":"55512312345",
"contactDirection":"",
"contactMethod":"Z08",
"interactionId":"5550848784",
"isResponsibleForPayingBill":"Yes"
},
"payload":{
"agentId":"USER001",
"contractAccountNumber":"55512312345",
"error":{
"55549271":{
"registers":{
"001":{
"isPlausible":false,
"deviceNumber":"55501223",
"register":"001",
"readingValue":"32641",
"readingDate":"2021-02-26T00:00:00.000Z"
}
},
"errors":[
{
"contractNumber":"55501231",
"language":"EN",
"errorCode":"62",
"errorText":"Error Text1",
"isHardError":false
},
{
"contractNumber":"55501232",
"language":"EN",
"errorCode":"62",
"errorText":"Error Text2",
"isHardError":false
}
],
"bpNumber":"5557273667"
},
"55583693":{
"registers":{
"001":{
"isPlausible":false,
"deviceNumber":"555121212",
"register":"001",
"readingValue":"00964",
"readingDate":"2021-02-26T00:00:00.000Z"
}
},
"errors":[
],
"bpNumber":"555123123"
}
}
}
}'
FROM
dual
)
SELECT
JSON_QUERY(data, '$.payload.error.*.registers.*[*].readingValue') AS reading_value
FROM
test_table;
UPDATE 2:
Solved, this would do the trick, upvoting the first comment.
JSON_QUERY(data, '$.payload.error.*.registers.*.readingValue' WITH WRAPPER) AS read_value
As I explained in the comment to your question, if you are getting that result from the JSON you posted, you are not using JSON_QUERY(); you must be using JSON_VALUE(). Either that, or there's something else you didn't share with us.
In any case, let's say you are using JSON_VALUE() with the arguments you showed. You are asking, how can you modify the path so that the top-level attribute name is not hard-coded. That is trivial: use asterisk (*) instead of the hard-coded name. (This would work the same with JSON_QUERY() - it's about JSON paths, not the specific function that uses them.)
with test_table (data) as (
select
'{
"59668509":{
"registers":{
"001":{
"isPlausible":false,
"deviceNumber":"40157471",
"register":"001",
"readingValue":"5295",
"readingDate":"2021-02-25T00:00:00.000Z"
}
}
}
}' from dual
)
select json_value (data, '$.*."registers"."001"."readingValue"'
returning number) as reading_value
from test_table
;
READING_VALUE
-------------
5295
As an aside that is not related to your question in any way: In your JSON you have an object with a single attribute named "registers", whose value is another object with a single attribute "001", and in turn, this object has an attribute named "register" with value "001". Does that make sense to you? It doesn't to me.

How to combine map and a filter for an XML-attribute in dataweave 2.0?

I trying to select a certain XML out fo a larger collection, using a filter to get only the one with the right attribute.
Without the filter I receive every last item in the current collection, but just can't come up with the correct syntax for the filter...
My XML-data:
<customer>
<profile>
<custom-attributes>
<custom-attribute attribute-id="customerCredit">0.0</custom-attribute>
<custom-attribute attribute-id="customerIDS">12345</custom-attribute>
<custom-attribute attribute-id="sscid">00001</custom-attribute>
</custom-attributes>
/<profile>
</customer>
My dataweave filter:
payload.ns0#customers.*ns0#customer map ( customer , indexOfCustomer ) -> {
(customer.ns0#profile.*ns0#"custom-attributes" filter ($.ns0#"custom-attribute".#"attribute-id" == "customerIDS") map {
"keys" : $
}
)
I would like to receive "keys: 12345" for the example above, but due to the filter it's simply skipped.
Your input doesnt match your dw script so it's hard to tell, there is no namespaces and "customers" element is missing.
But based on your input and your output you can achieve it via just a filter:
%dw 2.0
output application/json
---
payload.*customer map {
keys: $.profile."custom-attributes".*"custom-attribute" filter($.#"attribute-id"=="customerIDS")
}
Outputs:
[
{
"keys": [
"12345"
]
}
]
Or based on your example, no need to use map either:
%dw 2.0
output application/json
---
keys: payload.customer.profile."custom-attributes".*"custom-attribute" filter($.#"attribute-id"=="customerIDS")
If you provide a more detailed input and output you expect we can help more.

query for Time Stamp in mongo [duplicate]

I have a problem when querying mongoDB with nested objects notation:
db.messages.find( { headers : { From: "reservations#marriott.com" } } ).count()
0
db.messages.find( { 'headers.From': "reservations#marriott.com" } ).count()
5
I can't see what I am doing wrong. I am expecting nested object notation to return the same result as the dot notation query. Where am I wrong?
db.messages.find( { headers : { From: "reservations#marriott.com" } } )
This queries for documents where headers equals { From: ... }, i.e. contains no other fields.
db.messages.find( { 'headers.From': "reservations#marriott.com" } )
This only looks at the headers.From field, not affected by other fields contained in, or missing from, headers.
Dot-notation docs
Since there is a lot of confusion about queries MongoDB collection with sub-documents, I thought its worth to explain the above answers with examples:
First I have inserted only two objects in the collection namely: message as:
> db.messages.find().pretty()
{
"_id" : ObjectId("5cce8e417d2e7b3fe9c93c32"),
"headers" : {
"From" : "reservations#marriott.com"
}
}
{
"_id" : ObjectId("5cce8eb97d2e7b3fe9c93c33"),
"headers" : {
"From" : "reservations#marriott.com",
"To" : "kprasad.iitd#gmail.com"
}
}
>
So what is the result of query: db.messages.find({headers: {From: "reservations#marriott.com"} }).count()
It should be one because these queries for documents where headers equal to the object {From: "reservations#marriott.com"}, only i.e. contains no other fields or we should specify the entire sub-document as the value of a field.
So as per the answer from #Edmondo1984
Equality matches within sub-documents select documents if the subdocument matches exactly the specified sub-document, including the field order.
From the above statements, what is the below query result should be?
> db.messages.find({headers: {To: "kprasad.iitd#gmail.com", From: "reservations#marriott.com"} }).count()
0
And what if we will change the order of From and To i.e same as sub-documents of second documents?
> db.messages.find({headers: {From: "reservations#marriott.com", To: "kprasad.iitd#gmail.com"} }).count()
1
so, it matches exactly the specified sub-document, including the field order.
For using dot operator, I think it is very clear for every one. Let's see the result of below query:
> db.messages.find( { 'headers.From': "reservations#marriott.com" } ).count()
2
I hope these explanations with the above example will make someone more clarity on find query with sub-documents.
The two query mechanism work in different ways, as suggested in the docs at the section Subdocuments:
When the field holds an embedded document (i.e, subdocument), you can either specify the entire subdocument as the value of a field, or “reach into” the subdocument using dot notation, to specify values for individual fields in the subdocument:
Equality matches within subdocuments select documents if the subdocument matches exactly the specified subdocument, including the field order.
In the following example, the query matches all documents where the value of the field producer is a subdocument that contains only the field company with the value 'ABC123' and the field address with the value '123 Street', in the exact order:
db.inventory.find( {
producer: {
company: 'ABC123',
address: '123 Street'
}
});

Dataweave Error for Null nodes

I have done coding in dataweava as
%dw 1.0
%input payload application/xml
%output application/xml skipNullOn="everywhere"
---
{((payload.*Order default []) map {
Order:{
Channel:$.#EnterpriseCode,
Code:$.#OrderNo,
Status:$.#Status,
OrderLines: {
(($.OrderLines.*OrderLine default []) map {
OrderLine:{
EntryNumber:"abc",
Status:$.#Status,
(($.OrderStatuses.*OrderStatus default []) map {
ShipDate:$.#StatusDate
})
}})}
}
}
)
}
But its giving error when assigning input as
<?xml version="1.0" encoding="UTF-8"?>
<Order EnterpriseCode="111" OrderNo="222" Status="Scheduled">
<OrderLines>
<OrderLine PrimeLineNo="2" Status="Shipped" OrderedQty="1000">
</OrderLine>
</OrderLines>
</Order>
Any suggestions here? I have tried default [] but its not working. When assigning null node its giving error. I have tried filter as filter ($ != '')
XML input example:
<?xml version="1.0" encoding="UTF-8"?>
<Order EnterpriseCode="111" OrderNo="222" Status="Scheduled">
<OrderLines>
<OrderLine PrimeLineNo="2" Status="Shipped" OrderedQty="1000">
<OrderStatuses>
<OrderStatus StatusDate="statusDate"></OrderStatus>
<OrderStatus StatusDate="statusDate"></OrderStatus>
</OrderStatuses>
</OrderLine>
<OrderLine PrimeLineNo="3" Status="Shipped3" OrderedQty="10003" ></OrderLine>
</OrderLines>
</Order>
Note: In your example there are spaces between OrderLine open tag and close tag, you have to fix it:
<OrderLine PrimeLineNo="3" Status="Shipped3" OrderedQty="10003" ></OrderLine>
Dataweave script:
%input payload application/xml
%output application/xml skipNullOn="everywhere"
---
{
((payload.*Order default []) map {
Order:{
Channel:$.#EnterpriseCode,
Code:$.#OrderNo,
Status:$.#Status,
OrderLines: {
(($.OrderLines.*OrderLine default []) map {
OrderLine:{
EntryNumber:"abc",
Status:$.#Status,
(($.OrderStatuses.*OrderStatus default []) map ((key,pos) -> {
ShipDate:key.#StatusDate
}) when $!='' otherwise {})
}
})
}
}
})
}
You can't map a value if it doesn't exist, so you have to use "when/otherwise" to verify the existence of the elements.
Try this:
This should solve your issue. (Unless not/otherwise) or (when/otherwise), any combination can be used as per your requirement. "Unless not" is recommended if ShipDate is present in most cases, else replace "unless not" with "when".
%dw 1.0
%input payload application/xml
%output application/xml skipNullOn="everywhere"
---
{
(
(payload.*Order default []) map {
Order: {
Channel:$.#EnterpriseCode,
Code:$.#OrderNo,
Status:$.#Status,
OrderLines: {
(
($.OrderLines.*OrderLine default []) map ({
OrderLine: {
EntryNumber:"abc",
Status:$.#Status,
(
($.OrderStatuses.*OrderStatus) map {
ShipDate:$.#StatusDate
}
)
}
}) unless not $.OrderLines.*OrderLine.OrderStatuses? otherwise {
OrderLine: {
EntryNumber:"abc",
Status:$.#Status
}
}
)
}
}
}
)
}
Try following approaches:
use "SkipNullOn" %output application/xml skipNullOn="everywhere"
You can use when condition as shown below yourField: "null" when
payload.yourField == null otherwise payload.yourField
Giving below the structure definition of Mule Message Object has
Message
Inbound Property
Outbound Property
Payload
Variable
Flow Variable
Session Variable
Attachment
Exception Payload
When a connector of a flow (listening on a port) receives the payload its called Inbound endpoint.
When in a flow we have a connectore placed in the middle and send a payload its called Oubound endpoint. Here the all the outbound properties sent to the Http Outbound flow become Inbound Properties within that flow.
For detailed explanation see the link below.
https://docs.mulesoft.com/mule-user-guide/v/3.8/mule-message-structure.