I need value from MySQL send into PLC via OPC UA (in NODE-RED). Everything works ok, but I don't know how to get pure value without descriptions of array etc.
I use this code:
SELECT `user_info` FROM `users` WHERE `user_name` LIKE 'Lukas'
The answer is:
array[1]
0: object
user_info: "6"
If I send it to PLC as STRING the value in PLC is:
[object Object]
Can I edit the code somehow? I need answer only:
6
Thank you
The answer is array[1] 0: object user_info: "6"
I assume you've copied that out of the Debug window which shows you the exact structure of the payload you've received.
That is saying, the payload is an array with a single element. That element is an object with a user_info property of value 6.
In other words:
[
{
"user_info": "6"
}
]
In which case, to access the value you would use:
msg.payload[0].user_info
For example, a Function node to pull that value out and put it into the payload would be:
msg.payload = msg.payload[0].user_info;
return msg;
Or you could use a Change node to set the value of msg.payload to the value of msg.payload[0].user_info.
Related
I have a json object like so:
{
_id: "12345",
identifier: [
{
value: "1",
system: "system1",
text: "text!"
},
{
value: "2",
system: "system1"
}
]
}
How can I use the XDevAPI SearchConditionStr to look for the specific combination of value + system in the identifier array? Something like this, but this doesn't seem to work...
collection.find("'${identifier.value}' IN identifier[*].value && '${identifier.system} IN identifier[*].system")
By using the IN operator, what happens underneath the covers is basically a call to JSON_CONTAINS().
So, if you call:
collection.find(":v IN identifier[*].value && :s IN identifier[*].system")
.bind('v', '1')
.bind('s', 'system1')
.execute()
What gets executed, in the end, is (simplified):
JSON_CONTAINS('["1", "2"]', '"2"') AND JSON_CONTAINS('["system1", "system1"]', '"system1"')
In this case, both those conditions are true, and the document will be returned.
The atomic unit is the document (not a slice of that document). So, in your case, regardless of the value of value and/or system, you are still looking for the same document (the one whose _id is '12345'). Using such a statement, the document is either returned if all search values are part of it, and it is not returned if one is not.
For instance, the following would not yield any results:
collection.find(":v IN identifier[*].value && :s IN identifier[*].system")
.bind('v', '1')
.bind('s', 'system2')
.execute()
EDIT: Potential workaround
I don't think using the CRUD API will allow to perform this kind of "cherry-picking", but you can always use SQL. In that case, one strategy that comes to mind is to use JSON_SEARCH() for retrieving an array of paths corresponding to each value in the scope of identifier[*].value and identifier[*].system i.e. the array indexes and use JSON_OVERLAPS() to ensure they are equal.
session.sql(`select * from collection WHERE json_overlaps(json_search(json_extract(doc, '$.identifier[*].value'), 'all', ?), json_search(json_extract(doc, '$.identifier[*].system'), 'all', ?))`)
.bind('2', 'system1')
.execute()
In this case, the result set will only include documents where the identifier array contains at least one JSON object element where value is equal to '2' and system is equal to system1. The filter is effectively applied over individual array items and not in aggregate, like on a basic IN operation.
Disclaimer: I'm the lead developer of the MySQL X DevAPI Connector for Node.js
Most examples deal with the book store example from Stefan Gössner, however I'm struggling to define the correct JsonPath expression for a simple object (no array):
{ "Id": 1, "Name": "Test" }
To check if this json contains Id = 1.
I tried the following expression: $..?[(#.Id == 1]), but this does find any matches using Json.NET?
Also tried Manatee.Json for parsing, and there it seems the jsonpath expression could be like $[?($.Id == 1)] ?
The path that you posted is not valid. I think you meant $..[?(#.Id == 1)] (some characters were out of order). My answer assumes this.
The JSON Path that you're using indicates that the item you're looking for should be in an array.
$ start
.. recursive search (1)
[ array item specification
?( item-based query
#.Id == 1 where the item is an object with an "Id" with value == 1 at the root
) end item-based query
] end array item specification
(1) the conditions following this could match a value no matter how deep in the hierarchy it exists
You want to just navigate the object directly. Using $.Id will return 1, which you can validate in your application.
All of that said...
It sounds to me like you want to validate that the Id property is 1 rather than to search an array for an object where the Id property is 1. To do this, you want JSON Schema, not JSON Path.
JSON Path is a query language for searching for values which meet certain conditions (e.g. an object where Id == 1.
JSON Schema is for validating that the JSON meet certain requirements (your data's in the right shape). A JSON Schema to validate that your object has a value of 1 could be something like
{
"properties": {
"Id": {"const":1}
}
}
Granted this isn't very useful because it'll only validate that the Id property is 1, which ideally should only be true for one object.
I am working with:
Spring MVC Test
Hamcrest
JsonPath
I have the following how a response from the server:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[application/json;charset=UTF-8]}
Content type = application/json;charset=UTF-8
Body = {
"id" : "100",
"nombre" : "Jesús Você",
"apellido" : "Mão Nuñez",
"fecha" : "1977-12-08"
}
Forwarded URL = null
Redirected URL = null
The following works as expected (is valid):
.andExpect(jsonPath("$").exists())
.andExpect(jsonPath("$", notNullValue()))
.andExpect(jsonPath("$", isA(LinkedHashMap.class)))
.andExpect(jsonPath("$.*").exists())
.andExpect(jsonPath("$.*", notNullValue()))
.andExpect(jsonPath("$.*", isA(JSONArray.class)))
.andExpect(jsonPath("$.*", hasSize(is(4))))
I need test that ("$") is 1. Confirm exists 1 item. It to confirm again the following:
Body = {
"id" : "100",
"nombre" : "Jesús Você",
"apellido" : "Mão Nuñez",
"fecha" : "1977-12-08"
}
I've tried:
.andExpect(jsonPath("$", hasSize(is(1))))
Observe the difference between $ and $.*, for the latter I know it counts the number of fields. But from the former I always get:
java.lang.AssertionError: JSON path "$"
Expected: a collection with size is <1>
but: was <{id=100, nombre=Jesús Você, apellido=Mão Nuñez, fecha=1977-12-08}>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18
'Seems' the data is not a collection, but remember that .andExpect(jsonPath("$", isA(LinkedHashMap.class))) pass. I am confused in someway.
Therefore is possible test that ("$") is 1.? If yes, how?.
I've read count members with jsonpath?
And says:
To test size of array: jsonPath("$", hasSize(4))
To count members of object: jsonPath("$.*", hasSize(4))
My data returned is not an array, it is a LinkedHashMap.class because if I use .andExpect(jsonPath("$").isArray()) I get:
java.lang.AssertionError: Expected an array at JSON path "$" but found: {id=100, nombre=Jesús Você, apellido=Mão Nuñez, fecha=1977-12-08}
Expected: an instance of java.util.List
but: <{id=100, nombre=Jesús Você, apellido=Mão Nuñez, fecha=1977-12-08}> is a java.util.LinkedHashMap
BTW: .andExpect(jsonPath("$.*").isArray()) pass.
To validate the size of a Map instead of:
.andExpect(jsonPath("$", hasSize(1)))
you should use:
.andExpect(jsonPath("$", aMapWithSize(1)))
Note: Check this link with org.hamcrest.Matchers javadoc
I am trying to use Groovy script for my Json response in soapui and finding if the property exists in my response. I used If statement as below. For what ever property name i use to check it returns only true statement even though if the property not exists. I am not sure whats wrong I am doing here.
import groovy.json.JsonSlurper
def slurper = new JsonSlurper()
def i = 0
responseContent = testRunner.testCase.getTestStepByName("DAY").getPropertyValue("response")
slurperresponse = new JsonSlurper().parseText(responseContent)
if(slurperresponse.day_details.activities.to_locans) {
println "************************"
res = "Crew_base found"
} else {
res = "Crew_base not found"
}
This is caused by a few things coming together:
Groovy returns a null for unknown keys
Groovy lets you use xpath type variable lookup, including if that goes via a nested list
Groovy truthy on a list is based on the list size - even if the list only contains null, if its not empty, then it evaluates to true.
Your comment above reveals the problem:
For valid property name
Fri Apr 22 16:01:19 EDT 2016:INFO:<java.util.ArrayList#260080 elementData=[[NYP, NYP]] size=1 modCount=1>
For invalid property name
Fri Apr 22 16:01:35 EDT 2016:INFO:<java.util.ArrayList#3e0 elementData=[[null, null]] size=1 modCount=1>
You see in both cases the result is a list (of lists) of two items - so always evaluates to true.
As a map, from your final comment where you print the dump of that variable, it looks like this:
[
day_details: [
[
fra_status:'', block_training_day:0, holiday_name:'', activities:[
[ from_location:'WAS', craft:'Conductor', departure_datetime:'2016-04-26T13:02:00-04:00', end_datetime:'2016-04-26T16:30:00-04:00', crew_base:'NYP', ends_next_day:false, description:'Unit', train_number:172, to_location:'NYP', arrival_datetime:'2016-04-26T16:30:00-04:00', zone:'Zone 2', start_datetime:'2016-04-26T12:52:00-04:00' ],
[ from_location:'NYP', craft:'Engineer', to_location:'WAS', zone:'Zone 2', start_datetime:'2016-04-26T17:55:00-04:00' ]
]
]
]
]
Reading that, you will see that day_details and activities are both nested lists (hence the two lists in the response - so groovy navigates to each of the maps inside activities and looks for the key to_locans - not finding the key, it returns null, and puts those two nulls into a list.
Changing the if check to the following will work as you originally intended (that is with the assumption that you only want to ever consider the first element in each of those lists):
if (slurperresponse.day_details[0].activities[0].to_locans){
I'm trying to process the following with an JSON Input step:
{"address":[
{"AddressId":"1_1","Street":"A Street"},
{"AddressId":"1_101","Street":"Another Street"},
{"AddressId":"1_102","Street":"One more street", "Locality":"Buenos Aires"},
{"AddressId":"1_102","Locality":"New York"}
]}
However this seems not to be possible:
Json Input.0 - ERROR (version 4.2.1-stable, build 15952 from 2011-10-25 15.27.10 by buildguy) :
The data structure is not the same inside the resource!
We found 1 values for json path [$..Locality], which is different that the number retourned for path [$..Street] (3509 values).
We MUST have the same number of values for all paths.
The step provides Ignore Missing Path flag but it only works if all the rows misses the same path. In that case that step acts as as expected an fills the missing values with null.
This limits the power of this step to read uneven data, which was really one of my priorities.
My step Fields are defined as follows:
Am I missing something? Is this the correct behavior?
What I have done is use JSON Input using $.address[*] to read to a jsonRow field the full map of each element p.e:
{"address":[
{"AddressId":"1_1","Street":"A Street"},
{"AddressId":"1_101","Street":"Another Street"},
{"AddressId":"1_102","Street":"One more street", "Locality":"Buenos Aires"},
{"AddressId":"1_102","Locality":"New York"}
]}
This results in 4 jsonRows one for each element, p.e. jsonRow = {"AddressId":"1_101","Street":"Another Street"}. Then using a Javascript step I map my values using this:
var AddressId = getFromMap('AddressId', jsonRow);
var Street = getFromMap('Street', jsonRow);
var Locality = getFromMap('Locality', jsonRow);
In a second script tab I inserted minified JSON parse code from https://github.com/douglascrockford/JSON-js and the getFromMap function:
function getFromMap(key,jsonRow){
try{
var map = JSON.parse(jsonRow);
}
catch(e){
var message = "Unparsable JSON: "+jsonRow+" Desc: "+e.message;
var nr_errors = 1;
var field = "jsonRow";
var errcode = "JSON_PARSE";
_step_.putError(getInputRowMeta(), row, nr_errors, message, field, errcode);
trans_Status = SKIP_TRANSFORMATION;
return null;
}
if(map[key] == undefined){
return null;
}
trans_Status = CONTINUE_TRANSFORMATION;
return map[key]
}
You can solve this by changing the JSONPath and splitting up the steps in two JSON input steps. The following website explains a lot about JSONPath: http://goessner.net/articles/JsonPath/
$..AddressId
Does in fact return all the AddressId's in the address array, BUT since Pentaho is using grid rows for input and output [4 rows x 3 columns], it can't handle a missing value aka null value when you want as results return all the Streets (3 rows) and return all the Locality (2 rows), simply because there are no null values in the array itself as in you can't drive out of your garage with 3 wheels on your car instead of the usual 4.
I guess your script returns null (where X is zero) values like:
A S X
A S X
A S L
A X L
The scripting step can be avoided same by changing the Fields path of the first JSONinput step into:
$.address[*]
This is to retrieve all the 4 address lines. Create a next JSONinput step based on the new source field which contains the address line(s) to retrieve the address details per line:
$.AddressId
$.Street
$.Locality
This yields the null values on the four address lines when a address details is not available in an address line.