object stocking in node.js - node.js

How can I create resuable blank objects in node.js? For example :
In file1 :
var Result = {
error :false,
errorReport :[]
}
exports.Result = Result;
In file 2 :
var result = require('../file1');
exports.doSomething = function(){
var output = result.Result;
output.error = true;
output.errorReport = some_error_array;
}
Now, everytime I invoke doSomething(), it is obvious that the last result will be cached.
But, everytime I invoke doSomething(), i want a fresh object as it is declared in Result without any extra programming (i dont want to reset attributes everytime i do some thing with Result object.
Am I missing any minor detail here ? please help me out

You could make it a class:
exports.Result = function() {
this.error = false;
this.errorReport = [];
};
// later on:
var output = new result.Result();
...
Or even make it fancy so that you can pass arguments:
exports.Result = function(error, errorReport) {
this.error = error === undefined ? false : error;
this.errorReport = errorReport === undefined ? [] : errorReport;
};
// later
var output = new result.Result(true, some_error_array);

Related

Blockly while loop argument

I have created a little maze with a robot and I use Blockly to generate code to try to solve it. I can move the robot using Javascript commands which are Blockly blocks. So far so good.
I am currently breaking my head over arguments of if-statements and while loops. Mainly, I have tried two things:
Blockly maze
create a variable, 'not_goal_reached' which says whether or not the robot has reached the goal position (cross). Code:
function not_done() {
var goal_location = get_goal_position()
var goal_x = goal_location[0];
var goal_y = goal_location[1];
console.log('in not done');
//console.log(player.x!= goal_x || player.y != goal_y)
return (player.x!= goal_x || player.y != goal_y);
};
Blockly.Blocks['not_goal_reached'] = {
init: function() {
this.appendDummyInput()
.appendField("not at goal")
this.setOutput(true, "Boolean");
this.setColour(230);
this.setTooltip('');
this.setHelpUrl('');
}
};
Blockly.JavaScript['not_goal_reached'] = function(block) {
var code = 'not_done()';
// TODO: Change ORDER_NONE to the correct strength.
//console.log(code)
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
However, when using this block in an If or While statement. I always get a Javascript error that does not help me to find the solution:
TypeError: Cannot read property 'toBoolean' of undefined
at Interpreter.stepConditionalExpression (acorn_interpreter.js:148)
at Interpreter.step (acorn_interpreter.js:45)
at nextStep (index.html:79)
I use the Acorn js interpreter:
window.LoopTrap = 2000;
//Blockly.JavaScript.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = Blockly.JavaScript.workspaceToCode(workspace);
console.log(code);
var myInterpreter = new Interpreter(code, initInterpreter);
//Blockly.JavaScript.INFINITE_LOOP_TRAP = null
var counter = 0;
function nextStep() {
try {
if (myInterpreter.step()) {
counter+=1;
console.log(counter);
if (counter < window.LoopTrap) {
window.setTimeout(nextStep, 30);
}
else {
throw "Infinite Loop!"
}
}
}
catch (e) {
//alert(e);
console.log(e)
}
}
nextStep();
Problem: javascript error I can not solve :(
I created my own While block that does not require input. This While block checks internally whether or not the robot has reached the goal and then processes the DO statements:
Blockly.Blocks['repeat_forever'] = {
init: function() {
this.appendDummyInput()
.appendField("While not at goal");
this.appendStatementInput("DO")
.appendField("Do");
this.setPreviousStatement(true);
this.setColour(230);
this.setTooltip('');
this.setHelpUrl('');
}
};
Blockly.JavaScript['repeat_forever'] = function(block) {
var branch = Blockly.JavaScript.statementToCode(block, 'DO');
// TODO: Assemble JavaScript into code variable.
//if (Blockly.JavaScript.INFINITE_LOOP_TRAP) {
// branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,
// '\'block_id_' + block.id + '\'') + branch;
// console.log(branch);
//}
var code = 'while (' + not_done() + ') {' + branch + '}';
console.log(code)
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
This works, BUT, here I have the problem that my internal function 'not_done' is only evaluated once (at code generation) to while(true) (since the first time the robot is of course not at the goal location yet). This block correctly applies the DO codes but does not halt (since while (true)). If I add quotes around 'not_done()' the function is evaluated once apparently, but then I receive the same Javascript error as above (Cannot read property 'toBoolean' of undefined)
Am I missing something here? Thanks a lot for your time!
Greetings
K
It seems that you setTimeout which cannot be reached while the while loop runs.

Return from then - nodejs

I am sort of new to NodeJS and I'm learning as I code but I can't wrap my head around Promise/then.
Here is the piece of code - I'm using a library function to Read database values.
var collection = 'Students';
var query = {};
query.name = 'name';
//readFromDatabse returns -{Function} a promise to return the document found, or null if not found
var temp = readFromDatabase(collection, query).then(function(studentData) {
var result = {
resultDetails: {
username: studentData.username,
password: studentData.password
}
};
return callback(null,resultDetails);
});
but when I read see the values in temp, it contains {"isFulfilled":false,"isRejected":false}!! how can I get the result details into temp?
You have to think of Promises as containers for values. readFromDatabase returns such a container, which might eventually hold the requested value unless the query fails. Your temp variable points to the container, but not the response. The properties isFullfilled and isRejected are attributes of the Promise telling you that it has neither been resolved with a value or rejected with an error.
To get to the response you have to use the then method. The function you register there will be called for you, when the query yields a result or an error.
var collection = 'Students';
var query = {};
query.name = 'name';
var temp = null;
readFromDatabase(collection, query).then(function(studentData) {
var result = {
resultDetails: {
username: studentData.username,
password: studentData.password
}
};
temp = result;
});
// temp is still null here

Using knex SELECT query results for another SELECT query

I am trying to run a PostgreSQL query with Knex and then use the results to run another query.
exports.buildBuoyFeaturesJSON = function (conditionA, conditionB) {
var query = null;
var selectedFields = knex.select
(
knex.raw('t_record.id AS id'),
...
knex.raw('t_record.latitude AS latitude'),
knex.raw('t_record.longitude AS longitude')
)
.from('t_record')
.then(function (response) {
var geometry_array = [];
var rows = response.rows;
var keys = [];
for (var key = 0; key <= rows.length - 1; key++) {
var geometry =
{
"id" : rows[key].id,
"type" : "Feature",
"geometry" : rows[key].geometry,
"properties" : {
...
"sensors" : []
}
};
keys.push(rows[key].id);
geometry_array.push(geometry);
}
getMeasurementsAndSensors(keys, geometry_array);
});
};
The latter function uses some of the results from the previous function. Due to asynchronous nature of Knex, I need to call the second function from inside the first function's .then() statement:
function getMeasurementsAndSensors (keys, geometry_array) {
var query = knex
.select
(
't_record_id',
'i_sensor_id',
'description',
'i_measurement_id',
't_sensor_name',
't_measurement_name',
'value',
'units'
)
.from('i_record')
...
.whereRaw('i_record.t_record_id IN (' + keys + ')')
.orderByRaw('t_record_id, i_sensor_id ASC')
.then(function (response) {
var rows = response.rows;
var t_record_id = 0;
var i_sensor_id = 0;
var record_counter = -1;
var sensor_counter = -1;
for (var records = 0; records <= rows.length -1; records++) {
if (t_record_id !== rows[records].t_record_id) {
t_record_id = rows[records].t_record_id;
record_counter++;
sensor_counter = -1;
}
if (i_sensor_id !== rows[records].i_sensor_id) {
i_sensor_id = rows[records].i_sensor_id;
geometry_array[record_counter].properties.sensors[++sensor_counter] =
{
'i_sensor_id' : rows[records].i_sensor_id,
't_sensor_name' : rows[records].t_sensor_name,
'description' : rows[records].description,
'measurements' : []
};
}
geometry_array[record_counter].properties.sensors[sensor_counter].measurements.push
({
'i_measurement_id': rows[records].i_measurement_id,
'measurement_name': rows[records].t_measurement_name,
'value': rows[records].value,
'units': rows[records].units
});
}
//wrapping features with metadata.
var feature_collection = GEOGRAPHY_METADATA;
feature_collection.features = geometry_array;
JSONToFile(feature_collection, 'buoy_features');
});
}
Currently I save end result to a JSON file because I couldn't get Promises to work. JSON is later used to power a small OpenLayers application, hence the JSON-ification after getting results.
I am quite sure that getting the data from a database, saving it to file, then accessing it from another process and using it for OpenLayers is a very redundant way to do it, but so far, it is the only one that works.
I know there are a lot of ways to make these functions work better, but I am new to promises and don't know how to work with them outside of most basic functions. Any suggestions how to make this code better are welcome.
All you appear to be missing is a bunch of returns.
Here are skeletonized versions of the two functions, including the necessary returns :
exports.buildBuoyFeaturesJSON = function(conditionA, conditionB) {
return knex.select (...)
^^^^^^
.from(...)
.then(function(response) {
// synchronous stuff
// synchronous stuff
return getMeasurementsAndSensors(keys, geometry_array);
^^^^^^
}).then(function(geometry_array) {
var feature_collection = GEOGRAPHY_METADATA;
feature_collection.features = geometry_array;
return feature_collection;
^^^^^^
});
};
function getMeasurementsAndSensors(keys, geometry_array) {
return knex.select(...)
^^^^^^
.from(...)
...
.whereRaw(...)
.orderByRaw(...)
.then(function(response) {
// heaps of synchronous stuff
// heaps of synchronous stuff
// heaps of synchronous stuff
return geometry_array;
^^^^^^^^^^^^^^^^^^^^^
});
}
I moved the feature_collection collection part into buildBuoyFeaturesJSON() on the basis that it seems to sit there more logically. If not, then it would be very simple to move it back into getMeasurementsAndSensors().
I have not tried to fix the additional issue highlighted by #vitaly-t.

Multiple queries inside mongodb query

I'm having an issue when trying to query based on the result of another query on mongodb.
I'm trying to make an initial query and then do another query for each one of the result of the first query. The reason I'm doing it like this is because I have two different collections and I need to join some data from one collection with the data of the other collection. In a SQL world I could easily do this with a JOIN, but as I'm using mongodb in this one I can't really use JOINs, so I guessed doing a for loop inside the first query's callback function would be the way to go.
Here's the code I'm using...
var resultSet = [];
db.get('busstopcollection').find({id_bus_stop: parseInt(req.body.busstopid)}, function(e, docs){
if(e || docs.length === 0) {
console.log("Sorry, wrong id.");
return e;
}
for(var m=0; m<docs.length; m++){
var auxRes = {};
auxRes.id_bus = docs[m].id_bus;
auxRes.id_bus_stop = docs[m].id_bus_stop;
auxRes.coord_x = docs[m].coord_x;
auxRes.coord_y = docs[m].coord_y;
auxRes.id_bus_variation = docs[m].id_bus_variation;
db.get('buscollection').find({id_bus: parseInt(docs[m].id_bus)}, function(e, busDocs){
auxRes.s_origin_description = busDocs[0].s_origin_description;
auxRes.s_destination_description = busDocs[0].id_destination_description;
resultSet.push(auxRes);
});
res.send(JSON.stringify(resultSet));
}
});
I need to res.send the resultSet array after all the values have been added.
I've tried some other ways of doing this, but the thing is that when the res.send line is reached the second query hasn't finished at all. I also tried doing that inside the inner query's callback, but I need to check if it's the last in the for loop, and checking the value o m won't do it as it always is equivalent to docs.length.
As far as I know there's no such thing as a synchronous query in mongodb, but maybe I'm wrong.
What's the right way of doing this?
EDIT
I found a way around it, but I'm sure there's got to be a better way. Here's how I'm doing it...
db.get('busstopcollection').find({id_bus_stop: parseInt(req.body.busstopid)}, function(e, docs){
if(e || docs.length === 0) {
console.log("Ha ocurrido un error, no existe esa parada");
return e;
}
var busIDs = [];
for(var m=0; m<docs.length; m++){
busIDs.push(parseInt(docs[m].id_bus));
var auxRes = {};
auxRes.id_bus = docs[m].id_bus;
auxRes.id_bus_stop = docs[m].id_bus_stop;
auxRes.coord_x = docs[m].coord_x;
auxRes.coord_y = docs[m].coord_y;
auxRes.id_bus_variation = docs[m].id_bus_variation;
resultSet.push(auxRes);
}
db.get('buscollection').find({id_bus: {$in: busIDs}}, function(e, busDocs){
for(var n = 0; n<busDocs.length; n++){
for(var k=0; k<resultSet.length; k++){
if(resultSet[k].id_bus == busDocs[n].id_bus){
resultSet[k].s_origin_description = busDocs[n].s_origin_description;
resultSet[k].s_destination_description = busDocs[n].id_destination_description;
}
}
}
res.send(JSON.stringify(resultSet));
});
});
Node.js behavior is asynchronous , programmer has to code taking consideration of this behavior. Use callbacks or promises or a flow control library . In your your program , you
have put mongo query inside loop , which is a bad approach of querying . Instead if querying multiple times , use $in operator . It will optimize your code performance and
solves your response sending problem also.
var resultSet = [];
db.get('busstopcollection').find({id_bus_stop: parseInt(req.body.busstopid)}, function(e, docs){
if(e || docs.length === 0) {
console.log("Sorry, wrong id.");
return e;
}
var bus_ids = [];
for(var m=0; m<docs.length; m++){
var auxRes = {};
auxRes.id_bus = docs[m].id_bus;
bus_ids.push(parseInt(docs[m].id_bus)); // collect all ids
auxRes.id_bus_stop = docs[m].id_bus_stop;
auxRes.coord_x = docs[m].coord_x;
auxRes.coord_y = docs[m].coord_y;
auxRes.id_bus_variation = docs[m].id_bus_variation;
resultSet.push(auxRes);
}
// Query at one time for all document
db.get('buscollection').find({id_bus: {$in : bus_ids}}).toArray( function(e, busDocs){
// Now find and merge in one go
busDocs.forEach(function(eachBusDoc){
for(var i=0,len = resultSet.length;i< len;i++){
if(resultSet[i].id_bus == busDocs.id_bus ){
resultSet[i].s_origin_description = eachBusDoc.s_origin_description;
resultSet[i].s_destination_description = eachBusDoc.id_destination_description;
}
}
});
res.send(JSON.stringify(resultSet));
});
});
Your updated solution in your question is generally fine, as using $in is an excellent way of fetching a set of results (you'll want to make sure that you've indexed the id_bus property).
Here are a few tweaks (with a bit of cleanup and optimization):
db.get('busstopcollection')
.find({id_bus_stop: parseInt(req.body.busstopid)}).toArray(function(e, docs){
var auxById = {}; // store a dictionary of all the results for later
if(e || docs === null || docs.length === 0) {
console.log("Ha ocurrido un error, no existe esa parada");
return e;
}
var busIDs = [];
docs.forEach(function(doc) {
busIDs.push(parseInt(doc.id_bus));
// consider just using the doc directly rather than copying each property
// especially if you're not manipulating any of the data as it passes
var auxRes = {
id_bus : doc.id_bus,
id_bus_stop : doc.id_bus_stop,
coord_x : doc.coord_x,
coord_y : doc.coord_y,
id_bus_variation : doc.id_bus_variation
};
// you could just use each doc directly ...
// var auxRes = doc; ??
// ** importantly, store off the id_bus for each one so you can
// ** avoid a costly loop trying to match an id below.
auxById[doc.id_bus] = auxRes;
resultSet.push(auxRes);
});
// might want to consider using a cursor ... here's an example
db.get('buscollection')
.find({id_bus: {$in: busIDs}}).each(function(e, busDoc){
// the last item in the cursor will be null
if (busDoc === null) {
res.send(JSON.stringify(resultSet));
return;
}
var res = auxById[busDoc.id_bus];
if (res) { // did we find it in our dictionary of results?
// yes, we did == copy the necessary field data
res.s_origin_description = busDoc.s_origin_description;
res.s_destination_description = busDoc.id_destination_description;
}
});
});

SP.Ribbon.WebPartComponent.getWebPartAdder() returns undefined

I am using the source at http://blog.symprogress.com/2010/11/ribbon-insert-any-web-part-using-javascript/ to handle user web part button click event.
The function 'addWebPart()' calls a function 'SP.Ribbon.WebPartComponent.getWebPartAdder()' which is supposed to return adder instance but sometimes it returns undefined.
If I add a while loop to wait for the instance value to return correctly, the browser in my VM stalls for some time. When an instance is returned, the browser becomes responsive again. This only happens in some instances.
I am using SharePoint 2013 and the section of code I am referring to is:
addWebPart = function (wpCategory, wpTitle) {
var webPartAdder = SP.Ribbon.WebPartComponent.getWebPartAdder();
while (webPartAdder == undefined)
webPartAdder = SP.Ribbon.WebPartComponent.getWebPartAdder();
// ... Other stuff ...
}
How can this issue be resolved?
For anyone looking for an answer to this question, turns out you have to call 'LoadWPAdderOnDemand()' function then wait for the event '_spEventWebPartAdderReady'. Then query for 'window.WPAdder':
addWebPartDelayed = function (webPartAdder, wpCategory, wpTitle) {
var webPart = findWebPart(webPartAdder, wpCategory, wpTitle);
if (webPart) {
var zone = WPAdder._zones[0];
var wpid = WPAdder._createWebpartPlaceholderInRte();
WPAdder.addItemToPageByItemIdAndZoneId(webPart.id, zone.id, 0, wpid);
}
else
alert('ERROR: Web part not found! Please try again after sometime.');
},
addWebPart = function (wpCategory, wpTitle) {
var webPartAdder = window.WPAdder;
if (webPartAdder == undefined) {
LoadWPAdderOnDemand();
ExecuteOrDelayUntilEventNotified(
function () {
var webPartAdder = window.WPAdder;
addWebPartDelayed(webPartAdder, wpCategory, wpTitle);
},
"_spEventWebPartAdderReady");
}
else
addWebPartDelayed(webPartAdder, wpCategory, wpTitle);
};

Resources