Firebase won't save keys with null values - javascript

I have an object like:
var _json = { "objects":[{
"type":"path", "originX":"center", "originY":"center", "left":48.59,
"top":132.5, "width":64.5,"height":173, "fill":null,"stroke":"#3f7cc4",
"strokeWidth":12,"strokeDashArray":null
}]}
I save this object using Firebase as:
var myDataRef = new Firebase(<...>);
myDataRef.child("saved_projects").child(authData.uid).update({'P3': _json});
But, when I retrieve the same using Firebase on method and get the value as:
snapshot.val()
I get the object but keys with null values got removed i.e. I only got:
{"objects":[ {"type":"path", "originX":"center",
"originY":"center","left":48.59, "top":132.5,"width":64.5,
"height":173, "stroke":"#3f7cc4","strokeWidth":12
}]}
This is causing me some weird issues since I'm using Fabric.js and it needs these values.
Please help!
EDIT / UPDATE(Hack)
For the time being, I'm using a weird HACK, before storing the object to Firebase I'm converting all the null values to 0. But I want to know a nicer way to do.
function recursivelyReplaceNullToZero(j) {
for (var i in j){
if (typeof j[i] === "object") {
recursivelyReplaceNullToZero(j[i]);
}
if (j[i] === null) {
j[i] = 0;
}
}
}
recursivelyReplaceNullToZero(_json);

For the time being I'm using a weird HACK, before storing the object to Firebase I'm converting all the null values to 0. But I want to know much nicer way, please!
function recursivelyReplaceNullToZero(j) {
for (var i in j){
if (typeof j[i] === "object") {
recursivelyReplaceNullToZero(j[i]);
}
if (j[i] === null) {
j[i] = 0;
}
}
}
recursivelyReplaceNullToZero(_json);

fill would be a type string and those can be empty in Firestore.
strokeDashArray would be a type array and those can contain empty strings as well (among other data types). See image below which is a screenshot of Firestore. You are correct about null though, it won't store properties with value null.
Remember though that Firestore is a document database, and is schema-less - meaning that not every document is required to have all fields (semi-structured).
So, instead of storing value-less properties, simply handle the possibility that the property may not be there in your code, e.g.,
if(doc.exists){
if(doc.data().fill){
// now you do what you want with the fill property
} else {
// there is no fill data
}
}

This is expected behavior. AFAIK json systems work like this.
You should instead in your code set nulls for the keys that are not present in the database.
As an analogy: think of the leading zeroes - you DON'T write in front of a number.

Related

JavaScript - Using localStorage to save numbers: how to extract numbers from localStorage [duplicate]

I store a lot of values in localStorage for an app and needed a way of converting the "string" back into a number - IF it was a number. The thought being if you force HTML <input type="number"> on your form, then the data going into the form and extracted from the form IS a number, but once stored - its converted to a string. So to repopulate that field later, you must read the localStorage value and convert it back to a number before repopulating the input field - otherwise you start getting a lot of reptitive warnings and sometimes errors because NUMBERS are expected, but localStorage is retrieving strings.
My method: Assuming the value is inputted as a number, then only a number (digits only) will be stored - thus you can assume only numbers will come out (even if they are a string). Knowing only numbers will come back allows for this:
var allVariables = {} ;
var reg = new RegExp(/^\d+$/) ; // this accounts for digits only
for (var x=0; x<localStorage.length;x++) {
var keyValue = localStorage.getItem(localStorage.key(x)) ;
if (reg.text(keyValue)) {
keyValue = parseInt(keyValue) ;
}
allVariables[localStorage.key(x)] = keyValue ;
}
I even expanded on this to account for true/false booleans...can't use 0/1 easily without get confused with a number. Another method I have seen is underscoring the key name to identify the typeof for later conversion:
ie:
key1_str
key2_boo
key3_int
key4_obj
key5_flo
Then identify the "_xxx" to convert that value appropriately.
I am asking to see others approach to this problem or suggestions and recommendations on how to improve it. Mine is not perfect...though neither is localStorage...but still looking for improvement.s
suppose you have "keyName" : "12345".
Tricky solution is var newInt = +localStorage.getItem('keyName')
this extra + will convert the string to integer.
Instead of storing lots of single keys you might consider storing whole objects to less numbers of storage keys that you stringfiy to json and parse when retrieving. JSON methods will retain type
var obj= {
id:100,
anotherProp:'foo'
}
localStorage.setItem('myObj',JSON.stringify(obj));
var newObj = JSON.parse(localStorage.getItem('myObj'));
console.log(typeof newObj.id)//number
try to convert:
function getProbablyNumberFromLocalStorage(key) {
var val = localStorage.getItem(key);
return (isNan(+val) || val==null) ? val : +val;
}

What is a PoliglotMap in GraalVM?

I am working with the org.graalvm.polyglot script engine in my Java11 project to evaluate a JavaScript.
The script to be evaluated returns a JavaScript array with two entries.
...
var result={};
result.isValid=false;
result.errorMessage = new Array();
result.errorMessage[0]='Somehing go wrong!';
result.errorMessage[1]='Somehingelse go wrong!';
....
In my java code I try to evaluate the result object:
Value resultValue = context.getBindings(languageId).getMember("result");
In my Eclipse Debugger I can see that I receive a PolyglotMap containing the expected values:
I can iterate over that map to get the values with a code like this:
...
try {
mapResult = resultValue.as(Map.class);
} catch (ClassCastException | IllegalStateException | PolyglotException e) {
logger.warning("Unable to convert result object");
return null;
}
Iterator it = mapResult.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String itemName = pair.getKey().toString();
Object itemObject = pair.getValue();
...
In this way I am able to extract the boolean 'isValid'. But with the object 'errorMessage' I struggle.
Inspecting the Object again within the Eclipse Debugger it looks like this:
If I test this object it is an instanceOf Map. But I am unable to get any of the values out of this object.
Can anybody help me to understand what exactly this object represents and how I can extract the both values 'Someting go wrong!' and 'Sometingelse go wrong!' ?
When I iterate over this second map it seems to be empty - even if the debugger shows me the correct values.
I'm not 100% sure why as(Map.class) behaves that way, it might be worth creating an issue on github to figure it out: github.com/oracle/graal
But if you access the values using the API without converting to a Map it would work as you expect:
var errorMessage = resultValue.getMember("errorMessage");
errorMessage.hasArrayElements(); // true
var _0th = errorMessage.getArrayElement(0);
var _1th = errorMessage.getArrayElement(1);
You can also convert the polyglotMap to Value and then do it:
val errorMessage = context.asValue(itemObject);
errorMessage.hasArrayElements(); // true
errorMessage.getArrayElement(0);
PolyglotMap of course has the get method. And the Value javadoc says that:
Map.class is supported if the value has Value.hasHashEntries() hash entries}, members or array elements. The returned map can be safely cast to Map. For value with members the key type is String. For value with array elements the key type is Long.
Can you try getting them with the Long keys?
There might be something obvious I'm missing, so in any case it's better to raise an issue on GitHub.

How can I fix this function to recursively search an object for all instances of a key?

I'm trying to traverse an object to find all instances of a key, and get any value associated with the key. (The object may have a key multiple times at different depths)
I find the value I want just fine, however when I try to step backwards from a recursive "TraverseQuestData" (after finding a value), I get stuck in an infinite loop.
I've been looking a this for hours now and can't seem to find where the issue is. Would appreciate any help I can get. Thanks!
//traverse table for search_key. add anything to returning data that is a value associated with the search key
function TraverseQuestData(quests, search_key, token_cap, token_partial){
level_data = []
for(var key of Object.keys(quests)){
var value = quests[key]
if(typeof(value) == "object"){
var extra_strings = _.cloneDeep(TraverseQuestData(value, search_key, token_cap, token_partial + key + '_'))
for(i=0; i < extra_strings.length; i++){
level_data.push(extra_strings[i]);
}
} else if(key == search_key){
level_data.push({
token: (token_partial + token_cap),
value: value
});
}
}
return level_data;
}
This is the result of a silly mistake.
level_data was not defined with var or let resulting in it sitting within the global scope. Properly scoping the variable fixed this!
This wasn't an infinite loop but due to the size of the objects was indistinguishable from one (the program crashed because there were too many steps)

What to do if there is no data in localStorage?

I'm in a dilemma, I have a search engine which I keep the last results, everything perfect until there.
The problem is that I do not know what to do if I do not have items already saved, ie if it is the first time I search.
if(localStorage.getItem("searchResults") === null) {
// I do not know what to do here ...
}
else {
// Here the code is supposed to do what it has to do
}
Should not I do anything, should I save an empty string, or would I have to change the logic I'm working on?
What are your friends, what are you doing? Thank you
I would have a variable called "noResults", and set it to false, when search results are 0, or you can make it fetch results from server. It's all about context and logic
You could set it to N/A:
if(localStorage.getItem("searchResults") === null) {
localStorage.setItem("searchResults", "N/A");
}
else {
// Here the code is supposed to do what it has to do
}
Or use the following, and when you check if searchResults is null, last search result should be empty.
if(localStorage.getItem("searchResults") !== null) {
// Here the code is supposed to do what it has to do
}
Maybe you don't need an if statement. The if statement provides you with code blocks that can be executed for truthy or falsely expressions.
Instead, use a logical OR || to define a default value.
var results = localStorage.getItem('searchResults') || 'No results...';

Javascript JSON Encode of associative array

I know there are several issues with JavaScript Array.push() method posted here, but I can't get the following example to work:
First of all, i got a global Array:
var results = new Array();
for (var i = 0; i < X.length; i++) {
results[i] = new Array();
}
Now this array should be filled on a button-event. All I want is to fill the Array with new Arrays and push some data to them. The following code should check if results[x][y] already is an Array (and create one if it's not) and push data to it.
So, in the end, there should be an Array (result) that contains X.length Arrays filled with an unknown number of new Arrays, each of them containing an unknown number of data:
function pushResult(result) {
if (typeof results[currentStim][currentDist] == 'undefined') {
results[currentStim][currentDist] = new Array();
}
results[currentStim][currentDist].push(result);
}
Problem is: It just doesn't work. I made sure that currentStim is never out of bounds, I made sure that the "if"-Statement is only accessed when needed (so the Array isn't overwritten with a new one) and I watched the return-value of push(), always throwring back a number representing the new array length. As expected, this number increases evertime a value is pushed to an Array.
However, when I finally call:
document.getElementById('results').value = JSON.stringify(results);
to pass results to my PHP-script, something like this will be passed:
[[],[[1]],[],[]]
push()was called MUCH more often than once (at least "1" is one of the results I wanted to be stored) and, as described, always returned an increasing arrayLength. How does that work? What happened to my data?
I testet this on Chrome as well as on Firefox, same result. It might be interesting that a seperate loop draws to a Canvas the same time, but that shouldn't interupt Array-Handling and onKey-Events, right?
Hope u can help me,
MA3o
EDIT:
pushResult is called like this:
// Handles Space-Events
function pushed(event) {
if (event.which == 32 && stimAlive) {
pushResult(1);
hitCurrent = true;
}
Where hitCurrent and stimAlive are just flags set somewhere else. Some code further the function pushedis registered as an event listener:
document.onkeydown = function(event) { pushed(event)}
All the functions are called correctly. Adding console.log(results) to every loop just shows the right Array, as far as I can see.
According to the comments, the problem might be that "currentDist" can be a float value.

Categories