Node-red not detecting null value - node.js

I am trying to build a flow, that reads sensor data and transfers by CANBUS. Sometimes, null data is coming what I mean is tempInt or ldrInt could be null.
var msg2 = {
payload:
{
"$class": "org.acme.testnetwork.UpdateSensorData",
"sampDevice": "houseMehmet",
"newTempVal": tempInt,
"newLightVal": ldrInt,
"timeStamp": Date().toString()
}
};
Although I can access msg.payload.newLightVal and set it to any value, in the case that its value is null, the control statement such below fails.
if(msg.payload.newLightVal===null){
msg.payload.newLightVal = -1 ;
}

Are you sure that tempInt and ldrInt are null and not undefined .
I think they may be undefined in which case replace === with == in the if statement i.e
if(msg.payload.newLightVal==null)
Edit : Since the msg.payload.newLightVal is NaN , this should be the if clause
if(msg.payload.newLightVal==null || isNaN(msg.payload.newLightVal))

Related

Node-red:node-function - missing "null" value in if condition

I'm using Node-Red and in node function I have:
...
res = dataTransform.transform();
//critic case: res = [{"pressure":null}];
key = Object.keys(res[0]);
if(res[0][[key]]!=null)
{
...
console.log("res: ", [key]+":"+res[0][[key]]);
}
on console.log I have always:
res: 0:[object Object]
And it enters in if-statement always (also when the "res[0][[key]]" is null).
What was I mistake?
Object.keys returns an array containing the keys of the Object. Your code is using that entire array rather than a value from within it.
In order to get to the value of pressure, you would use:
var keys = Object.keys(res[0]);
var key = keys[0];
if (res[0][key] != null) {
console.log(res[0][key]);
}

Unable to check if null

I don't understand why I am unable to check null? Here is my code,
Tag.find({name : 'foo'}).exec(function(tag){
console.log('tag : ' + tag); // It's a null
console.log('type : ' + typeof tag); // It's a object
if(!tag){console.log('true');}
else {console.log('false');}
});
I try a lot of way such as,
if(tag == null){console.log('true');}
else {console.log('false');}
In every way, I always got else condition though I got null from tag.
In JavaScript, typeof null === 'object' has always been the case. It's just one of those gotchas you have to remember. If you want to check for strictly null, do a strict equals check: tag === null. tag == null will return true if tag is null or if it is undefined.

GeoCoder gives default value for invalid zip codes

I am using Geocoder to get a location based on the ZIP code (I am restricting it to just the US). Everything works fine except that if I input an invalid zip (90123, for example), it gives me a default value instead of giving ZERO_RESULTS. The default value happens to be Denton, Texas (for all invalid codes). How can I prevent this from happening, or tell whether a code is invalid to avoid this issue?
I am using this code:
geocoder.geocode({ 'address': zip, componentRestrictions: {country: 'us'} }, function (results, status) {
if (status == google.maps.GeocoderStatus.ZERO_RESULTS) {
jQuery('#zipErrorId').html("INVALID");
}
if (status == google.maps.GeocoderStatus.OK) {
geocoder.geocode({'latLng': results[0].geometry.location}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
var cityState = getCityState(results);
// like Apple Valley, Minnesota
var cityStateArr = cityState.split('|');
---------------------------
}
}
});
}
Currently it is returning Prudential Tower in Boston, MA. Don't know why.
It sends back the value you entered. So in results.address_components.short_name, will be the value it returned. So for example if I search on "00000,United States", the results.address_components.short_name will be "02199" (the zip of the aforementioned building). If that doesn't match the value you gave it, it was probably an invalid zip.

node.js - Is there any proper way to parse JSON with large numbers? (long, bigint, int64)

When I parse this little piece of JSON:
{ "value" : 9223372036854775807 }
This is what I get:
{ hello: 9223372036854776000 }
Is there any way to parse it properly?
Not with built-in JSON.parse. You'll need to parse it manually and treat values as string (if you want to do arithmetics with them there is bignumber.js) You can use Douglas Crockford JSON.js library as a base for your parser.
EDIT2 ( 7 years after original answer ) - it might soon be possible to solve this using standard JSON api. Have a look at this TC39 proposal to add access to source string to a reviver function - https://github.com/tc39/proposal-json-parse-with-source
EDIT1: I created a package for you :)
var JSONbig = require('json-bigint');
var json = '{ "value" : 9223372036854775807, "v2": 123 }';
console.log('Input:', json);
console.log('');
console.log('node.js bult-in JSON:')
var r = JSON.parse(json);
console.log('JSON.parse(input).value : ', r.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSON.stringify(r));
console.log('\n\nbig number JSON:');
var r1 = JSONbig.parse(json);
console.log('JSON.parse(input).value : ', r1.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSONbig.stringify(r1));
Output:
Input: { "value" : 9223372036854775807, "v2": 123 }
node.js bult-in JSON:
JSON.parse(input).value : 9223372036854776000
JSON.stringify(JSON.parse(input)): {"value":9223372036854776000,"v2":123}
big number JSON:
JSON.parse(input).value : 9223372036854775807
JSON.stringify(JSON.parse(input)): {"value":9223372036854775807,"v2":123}
After searching something more clean - and finding only libs like jsonbigint, I just wrote my own solution. Is not the best, but it solves my problem. For those that are using Axios you can use it on transformResponse callback (this was my original problem - Axios parses the JSON and all bigInts cames wrong),
const jsonStr = `{"myBigInt":6028792033986383748, "someStr":"hello guys", "someNumber":123}`
const result = JSON.parse(jsonStr, (key, value) => {
if (typeof value === 'number' && !Number.isSafeInteger(value)) {
let strBig = jsonStr.match(new RegExp(`(?:"${key}":)(.*?)(?:,)`))[1] // get the original value using regex expression
return strBig //should be BigInt(strBig) - BigInt function is not working in this snippet
}
return value
})
console.log({
"original": JSON.parse(jsonStr),
"handled": result
})
A regular expression is difficult to get right for all cases.
Here is my attempt, but all I'm giving you is some extra test cases, not the solution. Likely you will want to replace a very specific attribute, and a more generic JSON parser (that handles separating out the properties, but leaves the numeric properties as strings) and then you can wrap that specific long number in quotes before continuing to parse into a javascript object.
let str = '{ "value" : -9223372036854775807, "value1" : "100", "strWNum": "Hi world: 42 is the answer", "arrayOfStrWNum": [":42, again.", "SOIs#1"], "arrayOfNum": [100,100,-9223372036854775807, 100, 42, 0, -1, 0.003] }'
let data = JSON.parse(str.replace(/([:][\s]*)(-?\d{1,90})([\s]*[\r\n,\}])/g, '$1"$2"$3'));
console.log(BigInt(data.value).toString());
console.log(data);
you can use this code for change big numbers to strings and later use BigInt(data.value)
let str = '{ "value" : -9223372036854775807, "value1" : "100" }'
let data = JSON.parse(str.replace(/([^"^\d])(-?\d{1,90})([^"^\d])/g, '$1"$2"$3'));
console.log(BigInt(data.value).toString());
console.log(data);

Mongodb $where query always true with nodejs

When I query my database with a function passed in the "$where" clause in nodejs, it always return me all documents in the db.
For example, if I do
var stream = timetables.find({$where: function() { return false; }}).stream();
it return me all the documents.
Instead, if I do
var stream = timetables.find({$where: 'function() { return false; }'}).stream();
the function is really executed, and this code doesn't return any document.
The problem is that if I convert in string my function the context's bindinds are removed, and I need them for more complex query. For example:
var n = 1;
var f = function() { return this.number == n; }
var stream = timetables.find({$where: f.toString()}).stream();
// error: n is not defined
Is this a normal behaviour? How can I solve my problem?
Please excuse me for my poor english!
First off, keep in mind that the $where operator should almost never be used for the reasons explained here (credit goes to #WiredPrairie).
Back to your issue, the approach you'd like to take won't work even in the mongodb shell (which explicitly allows naked js functions with the $where operator). The javascript code provided to the $where operator is executed on the mongo server and won't have access to the enclosing environment (the "context bindings").
> db.test.insert({a: 42})
> db.test.find({a: 42})
{ "_id" : ObjectId("5150433c73f604984a7dff91"), "a" : 42 }
> db.test.find({$where: function() { return this.a == 42 }}) // works
{ "_id" : ObjectId("5150433c73f604984a7dff91"), "a" : 42 }
> var local_var = 42
> db.test.find({$where: function() { return this.a == local_var }})
error: {
"$err" : "error on invocation of $where function:\nJS Error: ReferenceError: local_var is not defined nofile_b:1",
"code" : 10071
}
Moreover it looks like that the node.js native mongo driver behaves differently from the shell in that it doesn't automatically serialize a js function you provide in the query object and instead it likely drops the clause altogether. This will leave you with the equivalent of timetables.find({}) which will return all the documents in the collection.
This one is works for me , Just try to store a query as a string in one variable then concat your variable in query string,
var local_var = 42
var query = "{$where: function() { return this.a == "+local_var+"}}"
db.test.find(query)
Store your query into a varibale and use that variable at your find query. It works..... :D
The context will always be that of the mongo database, since the function is executed there. There is no way to share the context between the two instances. You have to rethink the way you query and come up with a different strategy.
You can use a wrapper to pass basic JSON objects, ie. (pardon coffee-script):
# That's the main wrapper.
wrap = (f, args...) ->
"function() { return (#{f}).apply(this, #{JSON.stringify(args)}) }"
# Example 1
where1 = (flag) ->
#myattr == 'foo' or flag
# Example 2 with different arguments
where2 = (foo, options = {}) ->
if foo == options.bar or #_id % 2 == 0
true
else
false
db.collection('coll1').count $where: wrap(where1, true), (err, count) ->
console.log err, count
db.collection('coll1').count $where: wrap(where2, true, bar: true), (err, count) ->
console.log err, count
Your functions are going to be passed as something like:
function () {
return (function (flag) {
return this.myattr === 'foo' || flag;
}).apply(this, [true])
}
...and example 2:
function () {
return (
function (foo, options) {
if (options == null) {
options = {};
}
if (foo === options.bar || this._id % 2 === 0) {
return true;
} else {
return false;
}
}
).apply(this, [ true, { "bar": true } ])
}
This is how it is supposed to be. The drivers don't translate the client code into the mongo function javascript code.
I'm assuming you are using Mongoose to query your database.
If you take a look at the actual Query object implementation, you'll find that only strings are valid arguments for the where prototype.
When using the where clause, you should use it along with the standard operators such as gt, lt that operates on in the path created by the where function.
Remember that Mongoose querying, as in Mongo, is by example, you may want to reconsider your query specification in a more descriptive fashion.

Resources