findOne returns undefined on the server - node.js

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;
}
});

Related

Getting values out of a mongoose function (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].

MongoDB returning a null, but query works separately

In a post function, I am trying to retrieve the nth activity of a user (since I have a dropdown that return the index number of the activity). When I run the query
collection.find({'local.email':req.user.local.email},
{'local.activities':{$slice : [currActivity,1]}});
I receive the correct activity object in Robo3T.
But, when I call the same query in Node inside a post function, it returns an undefined.
app.post('/addlog',function(req,res){
var currActivity = req.body.curAct;
var score = req.body.score;
var comment = req.body.reason;
mongoose.connect('mongodb://****:****#ds044907.mlab.com:44907/intraspect',function (err, database) {
if (err)
throw err
else
{
db = database;
var collection = db.collection('users');
var retrievedAct = collection.find({'local.email':req.user.local.email},
{'local.activities':{$slice : [currActivity,1]}}).toArray().then(console.log(retrievedAct));
if (retrievedAct.length > 0) { printjson (retrievedAct[0]); }
console.log(currActivity);
console.log(retrievedAct[0]);
// console.log(req.body.newAct);
collection.update({'local.activities.name':retrievedAct[0]},
{$push: {'local.activities.log' : {
comments: comment,
score: score,
log_time: Date.now()
}}})
.then(function(){
res.redirect('/homepage');
})
.catch(function() {
console.log('Error');
});
}
});
});
I checked that the currActivity variable does infact contain the integer value for the nth activity.
If you want the result of collection.find().toArray(), as specified in the docs, you have two options:
Passing a callback to .toArray() like you did with mongoose.connect()
Using the Promise that it returns if you don't pass a callback
Now you are doing neither of them.
Also, you are mixing callback style and Promises in your code. I recommend you unificate your code. If you are using a Node.js version bigger than 8, using async/await could be nice, it makes it simpler.

Bluebird promise: loop over mongoose result

I query author data from a MongoDB via Mongoose (MEAN environment). The author data also contains an array of books that the author wrote (-> results.books). Once received, I'd like to iterate through this array of books and check for certain values. This is my code so far.
return Author.findOne({_id: req.user._id}, '-username').execAsync()
.then(function(results) {
return Promise.each(results.books) //this line causes TypeError rejection
}).then(function(book){
console.log('book:'+book); // test output
if(book==='whatever‘){
//do foo
}
}).catch(function(err){
console.log('Error: '+err);
});
Unfortunately I can't get it to work as it keeps giving me a rejection TypeError for the line marked above. I tried to apply this solution here (Bluebird Promisfy.each, with for-loops and if-statements?) but it wouldn't work out as it also seems to be a different kind of problem.
Bluebird's Promise.each() takes an iterable AND a iterator callback function that will be called for each item in the iterable. You are not passing the callback function. The .then() handler after Promise.each() is called when the entire iteration is done. It looks like you're expecting that to be the iterator - that's not the case.
Bluebird doc for Promise.each() is here.
I'm not sure exactly what you're trying to accomplish, but perhaps this is what you want:
return Author.findOne({_id: req.user._id}, 'username').execAsync()
.then(function (results) {
return Promise.each(results.books, function(book) {
console.log('book:' + book); // test output
if (book === 'whatever‘) {
//do foo
}
});
}).then(function() {
// Promise.each() is done here
}).catch(function (err) {
console.log('Error: ' + err);
});

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

NodeJS render result of MySQL query properly

I got a MySQL query where I ask for the values in a specific field with the help of the SELECT statement. My question is: How do I get the value of the query ? When I render the template with my current code I receive following output on my page [object Object]. I have the following Code:
var network;
function query(sql, callback) {
connection.query(sql, function(err, rows) {
if (err) {
callback(err, null);
} else {
callback(rows);
res.render('index.hjs', { Mysql : network });
console.log(network);
}
});
}
query("SELECT testString FROM test", function(results){
network = results;
});
There are a couple of corrections in your code. Nothing wrong but just good practice. In error callback, you are sending two arguments but in actual query callback function, you are using only one argument.
Second thing is that res will be undefined inside query function. (Of course, unless you have it inside request handler, which spoils the purpose of having it as a function)
Without your database structure and code structure, this is the best I can do to help you.

Resources