"Evaluate" Function that is stored in MongoDB Server - javascript

My collection looks like this:
> db.projects_columns.find()
{ "_id" : "5b28866a13311e44a82e4b8d", "checkbox" : true }
{ "_id" : "5b28866a13311e44a82e4b8e", "field" : "_id", "title" : "ID", "sortable" : true }
{ "_id" : "5b28866a13311e44a82e4b8f", "field" : "Project", "title" : "Project", "editable" : { "title" : "Project", "placeholder" : "Project" } }
{ "_id" : "5b28866a13311e44a82e4b90", "field" : "Owner", "title" : "Owner", "editable" : { "title" : "Owner", "placeholder" : "Owner" } }
{ "_id" : "5b28866a13311e44a82e4b91", "field" : "Name #1", "title" : "Name #1", "editable" : { "title" : "Name #1", "placeholder" : "Name #1" } }
{ "_id" : "5b28866a13311e44a82e4b92", "field" : "Name #2", "title" : "Name #2", "editable" : { "title" : "Name #2", "placeholder" : "Name #2" } }
{ "_id" : "5b28866a13311e44a82e4b93", "field" : "Status", "title" : "Status", "editable" : { "title" : "Status", "type" : "select", "source" : [ { "value" : "", "text" : "Not Selected" }, { "value" : "Not Started", "text" : "Not Started" }, { "value" : "WIP", "text" : "WIP" }, { "value" : "Completed", "text" : "Completed" } ], "display" : "function (value, sourceData) { var colors = { 0: 'Gray', 1: '#E67C73', 2: '#F6B86B', 3: '#57BB8A' }; var status_ele = $.grep(sourceData, function(ele){ return ele.value == value; }); $(this).text(status_ele[0].text).css('color', colors[value]); }", "showbuttons" : false } }
You can see that in the very last document that I have stored a function as text.Now the idea is that I will request this data and will be in an Javascript Array format.
But I want to be able to have my function without the quotes! You can see that simply evaluating it will not work because I need to have it still needs to be inside of the object ready to be executed when the array is used.
How can I achieve this?
Thanks for any help!

There are two possible solutions, but neither particularly safe and you should strongly consider why you need to store functions as strings in the first place. That being said, you could do two things.
The simplest is to use eval. To do so, you would have to first parse the object like normal, and then set the property that you want to the result of eval-ing the function string, like so:
// Pass in whatever JSON you want to parse
var myObject = JSON.parse(myJSONString);
// Converts the string to a function
myObject.display = eval("(" + myObject.display + ")");
// Call the function with whatever parameters you want
myObject.display(param1, param2);
The additional parentheses are to make sure that evaluation works correctly. Note, that this is not considered safe by Mozilla and there is an explicit recommendation not to use eval.
The second option is to use the Function constructor. To do so, you would need to restructure your data so that you store the parameters separately, so you could do something like this:
var myObject = JSON.parse(myJSONString);
// displayParam1 and displayParam2 are the stored names of your parameters for the function
myObject.display = Function(myObject.displayParam1, myObject.displayParam2, myObject.display)
This method definitely takes more modification, so if you want to use your existing structure, I recommend eval. However, again, make sure that this is absolutely necessary because both are considered unsafe since outside actors could basically inject code into your server.

Related

How to filter firebase data based on timestamp using startAt & endAt

I am trying to filter firebase data using startAt and/or endAt.
My data is structured as below.
{
"notes" : {
"-LOs0Ikx4ydM5RatREM1" : {
"data" : {
"dueDate" : 1561629600000,
"description" : "Korewa nan desuka?!",
"createdAt" : 1539611900000,
"title" : "First "
},
"members" : {
"author" : "1212121212121212121212121212"
}
},
"-LOs0Ikx4ydM5RatREM2" : {
"data" : {
"dueDate" : 4004870448000,
"description": "Test"
"createdAt" : 1539611900000,
"title" : "Second"
},
"members" : {
"author" : "1212121212121212121212121212"
}
},
"-LhBt9msLFKqUQ-koI9W" : {
"data" : {
"dueDate" : 1564653600000,
"description" : "abc",
"createdAt" : 1560363158279,
"title" : "August 1"
},
"members" : {
"author" : "3434343434343434343434343434"
}
},
"-LhBtKdDrQv9eKuYdfCi" : {
"data" : {
"dueDate" : 1564653600000,
"description" : "abcdef",
"createdAt" : 1560363158279,
"title" : "August 2"
},
"members" : {
"author" : "3434343434343434343434343434"
}
}
}
}
What I wish is to fetch all "notes" where dueDate has passed.
const now = moment().valueOf() //Eg. 1561629500000
database.ref('notes/')
.orderByChild("dueDate")
.endAt(now)
.once("value", (snapshot) => {
console.log('Process expired notes')
snapshot.forEach( (data) => {
const obj = data.val()
console.log('Date comparison:', (now >= obj.data.alertDate))
...
The code above does not work, it returns all the objects from the example JSON. The console.log logs "False" for three out of four returned objects.
I could do a comparison and only process the objects that meets my criteria, but that would defeat the purpose.
I have indexed the database on ["notes\data\alertDate"].
What am I missing? I must have misinterpreted the documentation somehow. :)
Your dueDate property is nested under data, so you need to address is as data/dueDate:
database.ref('notes')
.orderByChild("data/dueDate")
You might want to include both a startAt() and endAt() clause, with just a reasonable value for startAt() and the specific value you're already using for endAt().

How to access a part of a JSON file

Im trying to access some data and keep getting errors no matter what I try. Please help.
"rain":{"3h":13.625} is the part of the JSON file I am trying to access.
Here is what I have tried:
var currentRain = data.rain.3h; Which is most logical as it worked before but the number is what is giving the error.
var currentRain = data.rain["3h"];
var currentRain = data.rain[0]["3h"];
var currentRain = data.rain["3h"][0];
UPDATE:
This is the JSON payload:
{ "base" : "stations",
"clouds" : { "all" : 92 },
"cod" : 200,
"coord" : { "lat" : -33.850000000000001,
"lon" : 151.22
},
"dt" : 1429558616,
"id" : 6619279,
"main" : { "grnd_level" : 1024.97,
"humidity" : 100,
"pressure" : 1024.97,
"sea_level" : 1031.0999999999999,
"temp" : 288.77699999999999,
"temp_max" : 288.77699999999999,
"temp_min" : 288.77699999999999
},
"name" : "City of Sydney",
"rain" : { "3h" : 13.625 },
"sys" : { "country" : "AU",
"message" : 0.0101,
"sunrise" : 1429474880,
"sunset" : 1429514809
},
"weather" : [ { "description" : "heavy intensity rain",
"icon" : "10n",
"id" : 502,
"main" : "Rain"
} ],
"wind" : { "deg" : 157.5,
"speed" : 8.3200000000000003
}
}
You'll need to use ["bracket notation"] to access this, since "3h" begins with a number. As MDN explains:
An object property name can be any valid JavaScript string, or anything that can be converted to a string, including the empty string. However, any property name that is not a valid JavaScript identifier (for example, a property name that has a space or a hyphen, or that starts with a number) can only be accessed using the square bracket notation.
This is the correct JSON:
{
"rain": {
"3h": 13.625
}
}
First you need to parse it and transform into an object:
var jsonToObject = JSON.parse('{"rain":{"3h":13.625}}');
You can now access it like this:
jsonToObject.rain["3h"]
Just use data["rain"]. If you need to parse it first do JSON.parse(data) and then data["rain"].
OUTPUT
console.log(data["rain"]);
> { '3h': 13.625 }
...keep in mind that will return an Object.

jstree get data after update

I pass some json data in jstree and then I update the tree.
For example my initial data is
[
{ "id" : "demo_root_1", "text" : "Root 1", "children" : true, "type" : "root" },
{ "id" : "demo_root_2", "text" : "Root 2", "type" : "root" }
]
I update it a little (simple rename). "Root 1" becomes "UPDATED". How can I get the updated version of my data in json format like below?
[
{ "id" : "demo_root_1", "text" : "UPDATED", "children" : true, "type" : "root" },
{ "id" : "demo_root_2", "text" : "Root 2", "type" : "root" }
]
Okay..so basically if you want to refresh the tree with the updated data, then after the updation code, call the jstree callback:
$(tree).jstree('refresh');
This will refresh the tree with the new json data.
let me know in case of further issues.

java.lang.ClassCastException calling RedQueryBuilderFactory.create with args

This line in my JS file:
RedQueryBuilderFactory.create(config,
'SELECT "x0"."title", "x0"."priority" FROM "ticket" "x0" WHERE ("x0"."status" = (?))',
[]
);
works fine witih an empty array as the 3rd parameter. This parameter is supposed to be an array of strings according to the documentation and any sample code I can find. When I pass a string in the array it fails:
RedQueryBuilderFactory.create(config,
'SELECT "x0"."title", "x0"."priority" FROM "ticket" "x0" WHERE ("x0"."status" = (?))',
['in_process']
);
I get java.lang.ClassCastException in the Safari console. Here's the related part of the config if it's relevant:
var config = {
meta : {
tables : [ {
"name" : "ticket",
"label" : "Ticket",
"columns" : [ {
"name" : "title",
"label" : "Title",
"type" : "STRING",
"size" : 255
}, {
"name" : "priority",
"label" : "Priority",
"type" : "REF"
} ],
fks : []
} ],
types : [ {
"name" : "REF",
"editor" : "SELECT",
"operators" : [ {
"name" : "IN",
"label" : "any of",
"cardinality" : "MULTI"
}]
} ]
}
};
Looks like this is a bug in passing in parameter values. Internally it is expecting a collection but this is not happening.
Best if you raise a https://github.com/salk31/RedQueryBuilder bug report here?
NB Should be "IN" not "="

Knockout mapping does represent wished for html

I have a problem with knockout mapping. I'm using knockout mapping plugin to represent a form that is serialized in JSON. It was working before using the knockout mapping but I need to use knockout mapping since I want my properties to be observable.
You can see the working html here : http://jsfiddle.net/etiennenoel/wG9SZ
Here's my not working javascript code:
var formData =
{"data":
[
{
"groupName" : "Properties",
"content" :
[
{
"title" : "Calculation Method",
"formType" : "select",
"value" :
[
{
"title" : "Voltage Drop - Unbalanced",
"selected" : true
},
{
"title" : "Voltage Drop - Balanced"
}
]
},
{
"title" : "Tolerance (% V)",
"formType" : "textBox",
"value" : 0.01
},
{
"title" : "Calculation Options",
"formType" : "radio",
"value" :
[
{
"title" : "Flat Start (at Nominal Conditions",
"checked" : false
} ,
{
"title" : "Assume Line Transposition",
"checked" : true
}
]
},
{
"title" : "Adjust Conductor Resistance at",
"formType" : "textBox",
"disabled" : true,
"value" : 77,
"appendLabel" : true,
"appendLabelText" : "°F"
}
]
},
{
"groupName" : "Properties",
"content" :
[
{
"title" : "Calculation Method",
"formType" : "select",
"value" :
[
{
"title" : "Voltage Drop - Unbalanced",
"selected" : true
},
{
"title" : "Voltage Drop - Balanced"
}
]
},
{
"title" : "Tolerance (% V)",
"formType" : "textBox",
"value" : 0.01
},
{
"title" : "Calculation Options",
"formType" : "radio",
"value" :
[
{
"title" : "Flat Start (at Nominal Conditions",
"checked" : false
} ,
{
"title" : "Assume Line Transposition",
"checked" : true
}
]
},
{
"title" : "Adjust Conductor Resistance at",
"formType" : "textBox",
"disabled" : true,
"value" : 77,
"appendLabel" : true,
"appendLabelText" : "°F"
}
]
}
]
};
ko.mapping.fromJS(formData);
Here's the jsfiddle of the same code: http://jsfiddle.net/etiennenoel/wG9SZ/3/
What is the problem between when I use mapping and when I don't use it ?
In your second case you forgot to ApplyBindings.
ko.applyBindings(formData);
I don't know if this is the case with your scenario, but it's worth a post.
I had issues with the mapping plugin, when I had a more complex viewmodel with nested properties or lists. It turned out that after mapping to an already constructed viewmodel, the sub-objects were no more observables. With this issue, for me this code worked, what I've found somewhere (unfortunately I already really don't know where). I called this function for my viewmodel after mapping to that.
function makeAllObservables(observable) {
// Loop through its children
for (var child in observable()) {
// If this child is not an observable and is an object
if ((!ko.isObservable(observable()[child])) && (typeof observable()[child] === "object")) {
// Make it an observable
observable()[child] = ko.observable(observable()[child]);
// Make all of its children observables
makeAllObservables(observable()[child]);
}
}
};
Usage (when updating the model from server response, the first line should not be there):
var model = ko.observable({});
ko.mapping.fromJS(myJSObject, {}, model);
makeAllObservables(model);
ko.applyBindings(model);
I ment mapping to an already constructed viewmodel for example, when you want to update your viewmodel with new JSON data from server. In that case I lost nested bindings without the code above.
UPDATE: I've found the source where I borrowed the technique from, here. Note that I slightly modified that code in that post, because somehow that was not working for me.
You need to bind the mapped viewmodel to the view:
ko.applyBindings(ko.mapping.fromJS(formData));
and since everything is now an observable the logic in the view needs to be changed to use the method syntax:
<!-- ko if: $data.formType() === "select" -->
To get the options to display, you need to tell knockout what the property name is on the object:
<select data-bind="options: $data.value, optionsText: 'title'"></select>

Categories

Resources