My aim is to use Azure Data Factory to copy data from one place to another using REST API.
The first part of the copying is using the ForEach activity to select parameters from a nested JSON/array. I have had problems with this nested JSON because of various error messages in the ForEach activity.
My JSON is of the following form:
(
{
"key_1": "value_1",
"key_2": [
"value_2_1",
"value_2_2"
]
}
)
and first I'm setting the #json conversion function in front of it:
#json(
'{
"key_1": "value_1",
"key_2": [
"value_2_1",
"value_2_2"
]
}'
)
Here you can see the Execute Pipeline object and its parameters:
I am setting this JSON as a parameter in the Execute Pipeline object. I am setting its type as an "Array". (For the record, I have still had similar error messages even though I have tried to change the parameter type to "String" or "Object".)
The ForEach activity is used to select an item from the nested JSON, which is written into a parameter.
This immediately produces the following error in the Execute Pipeline activity:
Operation on target... ...failed: The function 'length' expects its parameter to be an array or a string. The provided value is of type 'Object'.
So, even though I set the JSON parameter type to "Array", it is changed into "Object" when I debug the pipeline activity. See the error below:
Next, I tried to use the ADF #createArray function before my JSON text.
#createArray(
'{
"key_1": "value_1",
"key_2": [
"value_2_1",
"value_2_2"
]
}'
)
When debugging, the forEach activity throws me an error in the first Copy data activity:
The expression 'concat(item().SELECTING_key_1_FROM_MY_JSON))' cannot be evaluated because property 'key_1' cannot be selected. Property selection is not supported on values of type 'String'.
Please help me, what I am doing wrong in my attempts of converting the JSON to an array? What should I change in my code?
So far I have tried changing the parameter type and using various functions in the JSON dynamic content but with no luck.
update:
If you want change the filename in Copy Data --> Sink.
You can key in the dynamic content #concat(pipeline().parameters.Pip_Object.key_1,'.json') to rename the file.
Please correct me if I understand you wrong.
First, we should use Parameters to store the Json array as follows. Because Variables are not support to store the Json array. Variables are only support to store simple data type such as ["1","2","3"...].
Json array format should as follows:
[{"key_1": "value_1"},{"key_2": ["value_2_1","value_2_2"]}]
I created a simple test here. Then ForEach the Json array:
Inside ForEach1 activity, pass #item() to the object type parameter Pip_Object.
The Input is as follows:
Add dynamic content above using any combination of expressions, functions and system variables at for each settings
#activity('Get Metadata1').output.childItems
We ended up using two pipelines: a generic one and a specific one.
The generic one has the JSON as a parameter (JSON_PARAMETER), and we set it a default value in the following form
[{"key_1":"value_1","key_2":["value_2"]},{"key_1":"value_3","key_2":["value_2"]}, ...etc. ...}]
The generic pipeline has a forEach loop, in which that mentioned JSON parameter is called in Settings -> Items:
#JSON(pipeline().parameters.JSON_PARAMETER)
In the specific pipeline, there is an Execute Pipeline activity, where the JSON_PARAMETER is found in Settings -> Parameters. If the default value of JSON_PARAMETER is used, the field is left blank. If we want to change the parameter, before Execute Pipeline, we put a Set Variable activity where we change the Variables -> Value to:
#concat('
[
{"key_1":"value_1",
"key_2":
["value_2",
"value_3"
]
},
{"key_1":"value_3",
...and so on...
}
]
')
Related
I am struggling to select a property from a JSON array that I've stored in a variable (as an array). I receive the following error:
The execution of template action 'Select' failed: The evaluation of 'query' action >'where' expression '{
"Response": "#variables('UserEvents').responseStatus.response",
"trest": ""
}' failed: 'The template language expression >'variables('UserEvents').responseStatus.response' cannot be evaluated because property >'responseStatus' cannot be selected. Array elements can only be selected using an > integer index. Please see https://aka.ms/logicexpressions for usage details.'.
The JSON is below:
[
{
"value": [
{
"responseStatus": {
"response": "notResponded",
"time": "0001-01-01T00:00:00Z"
}
}
]
}
]
I'm trying to select the 'response' property only by using the following expression:
#variables('UserEvents').responseStatus.response
I have tried adding [0] to various parts of the above expression but it doesn't seem to make any difference. I am sure it's pretty simple and I'm just getting the syntax wrong, but am completely stuck!
Any help appreciated - thanks.
Adrian
#{
variables('UserEvents') ? ['value'] ? [0] ? ['response']
}
Try that. The integer index mentioned in the error is the way around this. May need to play around with the structure to make it match your data but [0] will make it select the first object within your value array.
There are 2 ways to get the properties inside a nested JSON
WAY - 1 (Try to get properties using For-each loop)
For this we need to use 2 for-each loops to retrieve the property inside the nested JSON After Parsing the JSON. Below is the screenshot of my logic app for your reference.
WAY - 2 (Using Dynamic Expression)
Here is the Expression that worked for me.
body('Parse_JSON')?[0]?['value']?[0]?['responseStatus']?['response']
Since it is in Array of Array format we need to mention the index of the array. Below is the screenshot of my logic app for your reference :
output :
I am trying to pull multiple json keyvalue data within any given JSON object, from a JSON file produced via an API call, for only the JSON objects that contain a specific value within a keyvalue pair; this specific value within a keyvalue pair is obtained via iterating through a list. Hard to articulate, so let me show you:
Here is a list (fake list representing my real list) I have containing the "specific value within a keyvalue pair" I'm interested in:
mylist = ['device1', 'device2', 'device3']
And here is the json file (significantly abridged, obviously) that I am reading from my python script:
[
{
"name": "device12345",
"type": "other",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": null
},
{
"name": "device2",
"type": "other",
"os_name": "Linux",
"os_version": null
},
{
"name": "device67890",
"type": "virtual",
"os_name": "Microsoft Windows Server 2012 R2 Standard",
"os_version": null
}
]
I want to iterate through mylist, and for each item in mylist that matches the json keyvalue key "name" in the json file, print the values for 'name' and 'os_name'. In this case, I should see a result where after iterating through mylist, device2 matches the 'name' key in the json object that contains {'name':'device2'}, and then prints BOTH the 'name' value ('device2') and the 'os_name' value ('Linux'), and then continues iterating through mylist for the next value to iterate through the json file.
My code that does not work; let us assume the json file was opened correctly in python and is defined as my_json_file with type List:
for i in mylist:
for key in my_json_file:
if key == i:
deviceName = i.get('name')
deviceOS = i.get('os_name')
print(deviceName)
print(deviceOS)
I think the problem here is that I can't figure out how to "identify" json objects that "match" items from mylist, since the json objects are "flat" (i.e. 'device2' in my json file doesn't have 'name' and 'os_name' nested under it, which would allow me to dict.get('device2') and then retrieve nested data).
Sorry if I did not understand your question clearly, but it appears you're trying to read values off of the list instead of the JSON file since you're looking at i.get instead of key.get when key is what actually contains the information.
And for the optimization issue, I'd recommend converting your list of devices into a set. You can then iterate through the JSON array and check if a given name is in the set instead of doing it the other way. The advantage is that sets can return if they contain an item in O(1) time, meaning it will significantly speed up the overall speed of the program to O(n) where n = size of json array.
for key in my_json_file:
if key.get('name') in my_list:
deviceName = key.get('name')
deviceOS = key.get('os_name')
print(deviceName)
print(deviceOS)
I'm making API requests to a service which returns a JSON object within the body.
I can't seem to get the value of a key called "properties" within groovy.
Everytime I call obj.properties i get the following back
{
"class": "org.json.JSONObject"
}
but if I call just the obj I get the expected JSON object
{
"dummy1": ,
"dummy2": false,
"dummy3": etsad,
"dummy4": asdfw,
"dummy5": qweqwe,
"dummy6": 123123,
"properties": {
"country": UK,
}
}
Likewise if I obj.dummy2 i get false it's only when I obj.properties do I get the above mentioned response
Notice groovy have a special handling for Object's properties, for example for number:
def y = 25
print y.properties
It will print [class:class java.lang.Integer]
So it's part of basic groovy object
See also an answer about getting non-synthetic properties from groovy object
As #daggett comment, you can use
obj.get('properties')
Check out this answer here on how to access the properties of objects.
The reason obj.properties isn't working is most likely due to the fact that every object will have properties, and in your case obj.properties is getting the properties of the JSON object and not the value associated with the key.
Instead of obj.properties, consider obj['properties']
I need to get the count of card from json file. For this I've used $.storedCards.cards.lenght
in JSON Extractor but it doesn't work. There is an error message:
Options AS_PATH_LIST and ALWAYS_RETURN_LIST are not allowed when using path functions!
After that I've tried JSR223 PostProcessor with next script on goovy
def jsonText = '''${AllCards}''' //${AllCards} has json value
def json = new JsonSlurper().parseText(jsonText)
log.info( "Json length---------->"+json.resource.size())
${CardsCount} = props.get("4") //vars.put(json.resource.size.toString())
but there is problem with set value to my variable. Or when i've created variable in Groovy it was impossible to use outside from script.
My json file
"storedCards":
{
"cards":
[
{
"CardId":"123",
"cardBrand":"Visa",
"lastFourDigits":"2968",
},
{
"CardId":"321",
"cardBrand":"Visa",
"lastFourDigits":"2968",
},
..........
],
How can i get the count of card and set to my Variables? what should i use for this?
Your JSON data seems to be invalid. Assuming you have the valid JSON like below, I'm answering your question.
{
"storedCards": {
"cards": [
{
"CardId": "123",
"cardBrand": "Visa",
"lastFourDigits": "2968"
},
{
"CardId": "321",
"cardBrand": "Visa",
"lastFourDigits": "2968"
}
]
}
}
You dont need to write Groovy code, you can resolve this using JSON Extractor. Instead of using length function, use JSON path predicate like this-
$.storedCards.cards[*]
Though Variable you used in JSON Extractor won't give the solution right away, another JMeter function helps - __RandomFromMultipleVars
Excerpt from documentation -
The RandomFromMultipleVars function returns a random value based on the variable values provided by Source Variables.
The variables can be simple or multi-valued as they can be generated by the following extractors:
Boundary Extractor
Regular Expression Extractor
CSS Selector Extractor
JSON Extractor
XPath Extractor
XPath2 Extractor
Multi-value vars are the ones that are extracted when you set -1 for
Match Numbers. This leads to creation of match number variable called
varName_matchNr and for each value to the creation of variable
varName_n where n = 1, 2, 3 etc.
So once you use the predicate, you will get the count in the yourVariableName_matchNr. Example:-
Hope this help.
I'm using a service to load my form data into an array in my angular2 app.
The data is stored like this:
arr = []
arr.push({title:name})
When I do a console.log(arr), it is shown as Object. What I need is to see it
as [ { 'title':name } ]. How can I achieve that?
you may use below,
JSON.stringify({ data: arr}, null, 4);
this will nicely format your data with indentation.
To print out readable information. You can use console.table() which is much easier to read than JSON:
console.table(data);
This function takes one mandatory argument data, which must be an array or an object, and one additional optional parameter columns.
It logs data as a table. Each element in the array (or enumerable property if data is an object) will be a row in the table
Example:
first convert your JSON string to Object using .parse() method and then you can print it in console using console.table('parsed sring goes here').
e.g.
const data = JSON.parse(jsonString);
console.table(data);
Please try using the JSON Pipe operator in the HTML file. As the JSON info was needed only for debugging purposes, this method was suitable for me. Sample given below:
<p>{{arr | json}}</p>
You could log each element of the array separately
arr.forEach(function(e){console.log(e)});
Since your array has just one element, this is the same as logging {'title':name}
you can print any object
console.log(this.anyObject);
when you write
console.log('any object' + this.anyObject);
this will print
any object [object Object]