Function returning data from db - node.js

I am a newbie to node js and I am using mongoose for my models.
I have a function namde check which has a isNameThere function which receives name string as parameter in it. It checks the Db and looks for the name string which is provided if user exist in this name this.isNameThere will return true
var check= function()
{
this.nameIsThere = false;
this.isNameThere= function(name){
userModel.find({firstname: name},function(err,result){
if(result)
{
this.nameIsThere= true;
}
})
return this.nameIsThere;
}
}
Even if the name exist as you guess the code above will return false because the nature of asynchronous programming. Is there a way to execute the return isNameThere after userModel.find executes. Or any other solution for this situation. Thanks All.

Careful with the semicolons, you forgot some. It´s also good practice in JavaScript to place opening brackets right next to the function header and not in the next line.
You can encapsulate the DB call in a function like this:
function checkForName (callback) {
userModel.find({firstname: name}, callback);
}
checkForName(function (err, result) {
if (result) {
nameIsThere = true;
//do something else
...
}
});
After all, it IS anychronous, so you will not get any synchronous return value.
There´s also another way: Promises. Some libraries for you to check out:
https://github.com/caolan/async
https://github.com/kriskowal/q

Related

flow of program execution of javascript functions in node.js project

I'm having trouble deleting an item from MongoDB array in a node.js program and found an annoying issue in flow of program execution.
Here's the code:
productController.deleteProduct = function(req,res){
productModel.findById(req.query.id,function(err, product){
if(err){
res.send(err);
}
if(storeController.deleteStoreProduct(product,res.locals.store,req)){
product.remove(function(err){
if(err){
res.send(err);
}
res.send('product deleted successfully');
});
}
else{
res.send('delete operation failed');
}
});
}
The above function runs fine. The problem is with the below function.
The above function calls storeController.deleteStoreProduct
Here's the code for storeController.deleteStoreProduct:
storeController.deleteStoreProduct = function(product, store, req){
var isDeleted = false;
storeModel.findById(store, function(err, foundStore){
if(product.category === "electronics"){
if(product.subcategory === "mobiles"){
console.log('beginning');
storeModel.update({"storeId":"store-456"}, {'$pull': {"electronics.mobiles": mongoose.Types.ObjectId(product._id)}});
console.log('yeah done!!');
isDeleted = true;
}
}
});
if(isDeleted === true){
console.log('isdeleted: true');
return true;
}
else{
console.log('isdeleted: false');
return false;
}
}
Here in the storeController.deleteStoreProduct function I have written console.log statements just for the debugging purpose.
When I run this program what it has to do is delete a particular item from storeModel collection but instead it outputs just the console.log statements; the console.log statement above the delete statement and the one below that statement executes fine, but the actual delete statement in the middle of these both console.log statements doesn't executes and neither does it throws an error.
output:
isdeleted: false
beginning
yeah done!!
Instead of running the program from the beginning, it directly goes to last if else statement in storeController.deleteStoreProduct function.
I couldn't understand what is happening here.
more details:
arguments in the function storeController.deleteStoreProduct(product,store,req) are
1.product
this is an object and is something like this:
{
"name":"asus zenfone 2",
"category": "electronics",
"subcategory":"mobiles",
"details":{
"specs":["5mp rear cam","2gb ram",16gb rom],
}
}
2.store
store is the _id of the store object in the mongodb.
3.req
This is the request object
The problem with your code is, you are calling asynchronous function storeModel.findById inside your storeController.deleteStoreProduct function and expect storeController.deleteStoreProduct to behave like a synchronous function.
Your storeController.deleteStoreProduct function is always going to return false.
your code does not print
isDeleted: true
eventhough item gets deleted properly since code block
console.log('isdeleted: true');
return true;
never gets executed.
you cant treat storeController.deleteStoreProduct as a synchronous function. You need to treat storeController.deleteStoreProduct as an asynchronous function by either make it a function which accepts a callback or making it a promise returning function.
Hope this helps.

Javascript function using promises and not returning the correct value

As a relative beginning in Javascript development, I'm trying to understand this problem I'm encountering in a function I've built that will be a part of the code to connect to a postgreSQL database.
In this function, I'm using the knex query builder method to check if a table exists in a remote database, and this method resolves to a boolean that indicates whether the string you specified matches with a table of the same name in the database. I've a provided a sample example of the knex syntax so people better understand the function.
knex.schema.hasTable('users').then(function(exists) {
if (!exists) {
return knex.schema.createTable('users', function(t) {
t.increments('id').primary();
t.string('first_name', 100);
t.string('last_name', 100);
t.text('bio');
});
}
});
I am trying to make my function return a boolean by using the .every Array method, which checks each array and should every index pass the condition defined, the .every method should return a true value, otherwise false. I've built a function which takes an array of schema keys, or names of tables, and passes it to the .every method. The .every method then uses the knex.schema.hasTable method to return a true or false.
My concern is that through many different configurations of the function, I have not been able to get it to return a correct value. Not only does it return an incorrect value, which may have something to do with .every, which I believe can return "truthey" values, but after defining the function, I will often get a "Function undefined" error when calling it later in the file. Here is a sample of my function - again I think it is moreso my poor understanding of how returns, promises and closures are working together, but if anyone has insight, it would be much appreciated.
var schemaTables = ['posts','users', 'misc'];
// should return Boolean
function checkTable() {
schemaTables.every(function(key) {
return dbInstance.schema.hasTable(key)
.then(function(exists) {
return exists;
});
});
}
console.log(checkTable(), 'checkTable function outside');
// console.log is returning undefined here, although in other situations,
I've seen it return true or false incorrectly.
Your function is not working properly for two reasons:
You are not returning the in the checkTable function declaration, so it will always return undefined.
You should write:
function checkTable() {
return schemaTables.every(function(key) {
return dbInstance.schema.hasTable(key)
.then(function(exists) {
return exists;
});
});
}
Anyway you will not get what you want just adding return. I'll explain why in the second point.
Array.prototype.every is expecting a truthy or falsey value syncronously but what the dbInstance.schema.hasTable returns is a Promise object (and an object, even if empty, is always truthy).
What you have to do now is checking if the tables exist asynchronously, i'll show you how:
var Promise = require("bluebird");
var schemaTables = ['posts', 'users', 'misc'];
function checkTable(tables, callback) {
// I'm mapping every table into a Promise
asyncTables = tables.map(function(table) {
return dbInstance.schema.hasTable(table)
.then(function(exists) {
if (!exists)
return Promise.reject("The table does not exists");
return Promise.resolve("The table exists");
});
});
// If all the tables exist, Promise.all return a promise that is fulfilled
// when all the items in the array are fulfilled.
// If any promise in the array rejects, the returned promise
// is rejected with the rejection reason.
Promise.all(asyncTables)
.then(function(result) {
// i pass a TRUE value to the callback if all the tables exist,
// if not i'm passing FALSE
callback(result.isFulfilled());
});
}
checkTable(schemaTables, function (result) {
// here result will be true or false, you can do whatever you want
// inside the callback with result, but it will be called ASYNCHRONOUSLY
console.log(result);
});
Notice that as i said before, you can't have a function that returns a true or false value synchronously, so the only thing you can do is passing a callback to checkTable that will execute as soon as the result is ready (when all the promises fulfill or when one of them rejects).
Or you can return Promise.all(asyncTables) and call then on checkTable it self, but i'll leave you this as exercise.
For more info about promises check:
The bluebird website
This wonderful article from Nolan Lawson
Thanks Cluk3 for the very comprehensive answer. I actually solved it myself by using the .every method in the async library. But yes, it was primarily due to both my misunderstanding regarding returns and asynchronous vs synchronous.
var checkTablesExist = function () {
// make sure that all tables exist
function checkTable(key, done) {
dbInstance.schema.hasTable(key)
.then(function(exists) {
return done(exists);
});
}
async.every(schemaTables, checkTable,
function(result) {
return result;
});
};
console.log(checkTablesExist());
// will now print true or false correctly

Node.js promises with mongoskin

I'm trying to avoid using callbacks when making mongodb queries. I'm using mongoskin to make calls like so:
req.db.collection('users').find().toArray(function (err, doc) {
res.json(doc);
});
In many cases I need to make multiple queries so I want to use Node.js promise library but I'm not sure how to wrap these functions as promises. Most of the examples I see are trivial for things like readFile, I'm guessing in this case I would need to wrap toArray somehow? Can this be done or would have to be something implemented by mongoskin?
An example could be any set of callbacks, find/insert, find/find/insert, find/update:
req.db.collection('users').find().toArray(function (err, doc) {
if (doc) {
req.db.collection('users').find().toArray(function (err, doc) {
// etc...
});
}
else {
// err
}
});
You can promisify the entire module like so with bluebird:
var Promise = require("bluebird");
var mongoskin = require("mongoskin");
Object.keys(mongoskin).forEach(function(key) {
var value = mongoskin[key];
if (typeof value === "function") {
Promise.promisifyAll(value);
Promise.promisifyAll(value.prototype);
}
});
Promise.promisifyAll(mongoskin);
This only needs to be done in one place for one time in your application, not anywhere in your application code.
After that you just use methods normally except with the Async suffix and don't pass callbacks:
req.db.collection('users').find().toArrayAsync()
.then(function(doc) {
if (doc) {
return req.db.collection('users').find().toArrayAsync();
}
})
.then(function(doc) {
if (doc) {
return req.db.collection('users').find().toArrayAsync();
}
})
.then(function(doc) {
if (doc) {
return req.db.collection('users').find().toArrayAsync();
}
});
So again, if you call a function like
foo(a, b, c, function(err, result) {
if (err) return console.log(err);
//Code
});
The promise-returning version is called like:
fooAsync(a, b, c).then(...)
(Uncaught errors are automatically logged so you don't need to check for them if you are only going to log it)
Just stumbled here with the same question and didn't love "promisfying" mongoskin so did a bit more digging and found monk. It's built on top of mongoskin, tidies up the API and returns
promises for all async calls. Probably worth a peek to anyone else who lands here.
Esailija's answer may work, but its not super efficient since you have to run db.collection on every single db call. I don't know exactly how expensive that is, but looking at the code in mongoskin, its non-trivial. Not only that, but it's globally modifying prototypes, which isn't very safe.
The way I do this with fibers futures is:
wrap the collection methods for each collection
on receiving the result, for methods that return a Cursor wrap the toArray method, call it and return the resulting future (for methods that don't return a cursor, you don't need to do anything else).
use the future as normal
like this:
var Future = require("fibers/future")
// note: when i originally wrote this answer fibers/futures didn't have a good/intuitive wrapping function; but as of 2014-08-18, it does have one
function futureWrap() {
// function
if(arguments.length === 1) {
var fn = arguments[0]
var object = undefined
// object, methodName
} else {
var object = arguments[0]
var fn = object[arguments[1]]
}
return function() {
var args = Array.prototype.slice.call(arguments)
var future = new Future
args.push(future.resolver())
var me = this
if(object) me = object
fn.apply(me, args)
return future
}
}
var methodsYouWantToHave = ['findOne', 'find', 'update', 'insert', 'remove', 'findAndModify']
var methods = {}
methodsYouWantToHave.forEach(function(method) {
internalMethods[method] = futureWrap(this.collection, method)
}.bind(this))
// use them
var document = methods.findOne({_id: 'a3jf938fj98j'}, {}).wait()
var documents = futureWrap(methods.find({x: 'whatever'}, {}).wait(), 'toArray')().wait()
If you don't want to use fibers, I'd recommend using the async-future module, which has a good wrap function built in too.

Node.js, Synchronize.js and return values

I'm using this wonderful sync module, synchronize.js - http://alexeypetrushin.github.io/synchronize/docs/index.html.
I've run into a situation where I have to get the return value of the sync'd function into the scope outside of the fiber. Here's a basic example of what I'm talking about:
var records = sync.fiber(function() {
var results = ... // some synchronized function
return results;
});
Whereas records would, in theory, contain the value of resultsfrom within the fiber scope. I've been reading up on futures (fibers/futures module) and how they might be used in this situation but I have yet to come up with anything close to working. I'd love some direction and/or a solution.
edit:
For a more thorough example of what I'm looking to accomplish:
// executes a stored procedure/function
exec: function (statement, parameters) {
init();
var request = new sql.Request(),
results;
processParams(parameters, request);
var res = sync.fiber(function(){
try {
var result = sync.await(request.execute(statement, sync.defers('recordsets', 'returnValue')));
results = result.recordsets.length > 0 ? result.recordsets[0] : [];
return results;
}
catch (e) {
console.log('error:connection:exec(): ' + e);
throw(e);
}
});
// though typical scope rules would mean that `results` has a
// value here, it's actually undefined.
// in theory, `res` would contain the return value from the `sync.fiber` callback
// which is our result set.
return res;
}
As you can see here, what I'd like to accomplish is to get the value of results in the primary scope, from the fiber's scope.
Now it does support it, use following form
var records = sync.fiber(function() {
var results = ... // some synchronized function
return results;
}, function(err, results){... /* do something with results */});
It's not a scope problem. This wont work because return res; executes before the fiber returns. That is why it's undefined.
You need to rewrite your exec function to take a callback. Then you could use synchronize.js on the exec function itself.

Conditionally call async function in Node

I have the following example code - the first part can result in an async call or not - either way it should continue. I cannot put the rest of the code within the async callback since it needs to run when condition is false. So how to do this?
if(condition) {
someAsyncRequest(function(error, result)) {
//do something then continue
}
}
//do this next whether condition is true or not
I assume that putting the code to come after in a function might be the way to go and call that function within the async call above or on an else call if condition is false - but is there an alternative way that doesn't require me breaking it up in functions?
A library I've used in Node quite often is Async (https://github.com/caolan/async). Last I checked this also has support for the browser so you should be able to npm / concat / minify this in your distribution. If you're using this on server-side only you should consider https://github.com/continuationlabs/insync, which is a slightly improved version of Async, with some of the browser support removed.
One of the common patterns I use when using conditional async calls is populate an array with the functions I want to use in order and pass that to async.waterfall.
I've included an example below.
var tasks = [];
if (conditionOne) {
tasks.push(functionOne);
}
if (conditionTwo) {
tasks.push(functionTwo);
}
if (conditionThree) {
tasks.push(functionThree);
}
async.waterfall(tasks, function (err, result) {
// do something with the result.
// if any functions in the task throws an error, this function is
// immediately called with err == <that error>
});
var functionOne = function(callback) {
// do something
// callback(null, some_result);
};
var functionTwo = function(previousResult, callback) {
// do something with previous result if needed
// callback(null, previousResult, some_result);
};
var functionThree = function(previousResult, callback) {
// do something with previous result if needed
// callback(null, some_result);
};
Of course you could use promises instead. In either case I like to avoid nesting callbacks by using async or promises.
Some of the things you can avoid by NOT using nested callbacks are variable collision, hoisting bugs, "marching" to the right > > > >, hard to read code, etc.
Just declare some other function to be run whenever you need it :
var otherFunc = function() {
//do this next whether condition is true or not
}
if(condition) {
someAsyncRequest(function(error, result)) {
//do something then continue
otherFunc();
}
} else {
otherFunc();
}
Just an another way to do it, this is how I abstracted the pattern. There might be some libraries (promises?) that handle the same thing.
function conditional(condition, conditional_fun, callback) {
if(condition)
return conditional_fun(callback);
return callback();
}
And then at the code you can write
conditional(something === undefined,
function(callback) {
fetch_that_something_async(function() {
callback();
});
},
function() {
/// ... This is where your code would continue
});
I would recommend using clojurescript which has an awesome core-async library which makes life super easy when dealing with async calls.
In your case, you would write something like this:
(go
(when condition
(<! (someAsyncRequest)))
(otherCodeToHappenWhetherConditionIsTrueOrNot))
Note the go macro which will cause the body to run asynchronously, and the <! function which will block until the async function will return. Due to the <! function being inside the when condition, it will only block if the condition is true.

Resources