Getting values out of a mongoose function (node JS) - node.js

I think I have misunderstood something fundamental about mongoose here.
I'm using .find() with mongoose to get a value from a DB but it's being returned as undefined when it exits the call back. Is there a way to pass this value out?
Thank you in advance,
Tim
function getNumberOfRegisteredPupils(sProg){
var numberOfPupils;
User.find({studyProgram: sProg}, (err, users)=>{
console.log(users.length); //logs correct value to terminal
return users.length; //returns undefined
});
}

Your function getNumberOfRegisteredPupils doesn't return anything (there is no return statement in that function, only inside a callback of User.find function!), hence undefined.
You want to either return a promise:
function getNumberOfRegisteredPupils(sProg){
return User.find({studyProgram: sProg}, (err, users)=>{
return users.length;
});
}
Or you can use async/await syntax as suggested in the comments:
async function getNumberOfRegisteredPupils(sProg){
const users = await User.find({studyProgram: sProg}).exec();
return users.length;
}
OT: However, if you are looking for getting only number of users, have a look at Model.count() [docs].

Related

Promise function not returning results

I'm using instagram-scraping module to display all posts with a specific hash tag but I get an issue using a function to return finded items.
// in my middleware
function getInstagramPostsByHashTag(hashtag) {
return ig.scrapeTag(hashtag).then(result => {
console.log(result); // all posts are displayed in my console
return result;
});
}
// in my ejs template i send the function getInstagramPostsByHashTag()
<%=getInstagramPostsByHashTag("instagram")%> // nothing is displayed
You can't return the posts from the function because the function has already returned at this point. That's because .then() is asynchronous. It executes the provided callback when the work (fetching the posts) is done, but the function continues to run after the call to .then(), and because you return nothing, you get nothing.
If you want a function to return the result of an asynchronous operation, you have to return a promise from the function itself. To help developers with that, there's the async function that automatically returns a promise. In an async function, you can wait for other promises with the await keyword. Your function would look like this as an async function:
async function getInstagramPostsByHashTag(hashtag) {
return await ig.scrapeTag(hashtag)
}
But this is redundant because it returns exactly the same as a direct call to ig.scrapeTag(hashtag) would do. I don't really know ejs but I think the best thing you could do is something like this (only pseudocode, again, I don't know how rendering with ejs works):
posts = insta.scrapeTag("blablabla")
then
ejs.render("<%=posts%>", {posts})

Can't get result outside the query function in express nodejs

I am trying to get the value of variable w_name outside query even I have defined w_name before query but cannot getting it after query. Please check the code and help:
connection.query('SELECT * FROM workstations WHERE id=?',[results[0].w_id],function(err,res,field){
w_name = res[0].name;
});
console.log(w_name);
console.log showing undefined but if I am putting console.log inside the query after w_name it is showing proper result. What's wrong in it?
connection.query(...params) is asynchronous function, which requires some time to read and get resulting data for query passed to it.
Defining console.log(w_name) prints undefined because result is not yet assigned to w_name variable. Whereas defining it inside callback function assigns value to w_name.
Check this article for understanding asynchronous javascript.
connection.query('SELECT * FROM workstations WHERE id=?',
[results[0].w_id],function(err,res,field){
w_name = res[0].name;
console.log(w_name);
});
NodeJs is asynchronous, It uses callback for the results.
The best solution as far as i know about your problem is given below:
async function myQuery(){
return new Promise((resolve,reject)=>{
connection.query('SELECT * FROM workstations WHERE id=?',[results[0].w_id],function(err,res,field){
resolve(res[0].name)
});
})
}
Now you can use then to get the value or use async await to get the value like this.
//this is where you would like to call that function.
async function index(){
let w_name = await myQuery()
console.log(w_name)
}
here you can use Promise() and resolve() the query of the result.
const w_name = await new Promise(function(resolve, reject) {
connection.query('SELECT * FROM workstations WHERE id=?', [results[0].w_id], function(err, res, field) {
if (err) throw err
resolve(res[0].name);
})
});
console.log(w_name);

NodeJS Sequelize returning data from query

Totally new to Javascript and Node. I am trying to get started with Sequelize as an ORM and did a simple query
var employeeList = Employee.findAll().then(function(result){
console.log(result.length);
console.log(result[0].employeeName);
//how do I return this to a variable with which I can do further processing
return result;
});
//do something with employeeList
employeeList[0].employeeName //cannot read property of undefined
While the console logs print out the right name the employeeList itself does not contain any data. I tried printing the employeeList and it shows the promise
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined }
I did skim through the promise concept but could not get an east example as to how to return the results from the promise to a variable outside the function. I thought returning the result would do t he trick. Am I missing something here? I can understand that I could work on the results within the promise function. If the scenario is to make two database calls and then process the results of both calls to return a merged result how could that be done without getting results to variables.
so based on your post on comments of using to independent queries I'd like to show you how to use them properly:
//Each request in it's own function to respect the single responsability principle
function getAllEmployees() {
return Employee
.findAll()
.then(function(employees){
//do some parsing/editing
//this then is not required if you don't want to change anything
return employees;
});
}
function doAnotherJob() {
return YourModel
.findAll()
.then(function(response) => {
//do some parsing/editing
//this then is not required if you don't want to change anything
return response;
});
}
function do2IndependentCalls() {
return Promise.all([
getAllEmployees(),
doAnotherJob()
]).then(([employees, secondRequest]) => {
//do the functionality you need
})
}
Another way of doing is use async await :
async function getEmployees(){
var employeeList = await Employee.findAll().then(function(result){
console.log(result.length);
console.log(result[0].employeeName);
return result;
});
employeeList[0].employeeName;
}
The then method returns a Promise, not your employee list.
If you want to use the employee list, you should either do that in the function passed to your existing then call, or in a subsequent then call, as shown below.
Employee
.findAll()
.then(function(el){
console.log(el.length);
console.log(el[0].employeeName);
return el;
})
.then(function(employeeList){
//do something with employeeList
employeeList[0].employeeName
});

findOne returns undefined on the server

Here is my code on the server:
Meteor.publish('currentRequest', function (requestId) {
console.log('from publish');
console.log(requestId) // The id is printed successfully
console.log(Requests.findOne({_id: requestId})) // returns undefined
return Requests.findOne({_id: requestId});
});
The item ID is printed but .findOne() doesn't seem to work as it returns undefined.
What am I doing wrong here?
The answer to your question will be: because there is no document satisfying your search query.
According to documentation:
Finds the first document that matches the selector, as ordered by sort and skip options. Returns undefined if no matching document is found.
Equivalent to find(selector, options).fetch()[0] with options.limit = 1.
Also, as it has been pointed by #GaëtanRouziès, this publication won't work, because .findOne returns document/undefined instead of cursor.
.findOne() return the response in asynchronus way. you need to pass a callback function to findOne and use return statement in callback function. Please take a look at the sample code below.
CollectionName.findOne({
query : query
}, function(err, resp) {
if (err) {
throw err;
} else {
return resp;
}
});

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

Resources