I am trying to pass search result of a sequelize query to pug, but its not working
res.render('search',{
stack_holder:find_stack_holder(),
});
function find_stack_holder(){
return db.poregister.findAll({
attributes: [[Sequelize.fn('DISTINCT', Sequelize.col('stack_holder')), 'stack_holder']],
})
}
However pug gets promise instead of actual data. Aren't promises supposed to resolve themselves when the actual data are needed?
findAll returns a Promise, so, you need to do something like this:
const findAllPromise = find_stack_holder();
findAllPromise.then(function(result) {
res.render('search',{
stack_holder: result,
});
});
function find_stack_holder() {
return db.poregister.findAll({
attributes: [[Sequelize.fn('DISTINCT', Sequelize.col('stack_holder')), 'stack_holder']],
});
}
Related
My goal is to create an abstracted POST function for an express running on Node similar to Django's inbuilt REST methods. As a part of my abstracted POST function I'm checking the database (mongo) for valid foreign keys, duplicates, etc..., which is where we are in the process here. The function below is the one that actually makes the first calls to mongo to check that the incoming foreign keys actually exist in the tables/collections that they should exist in.
In short, the inbuilt response functionality inside the native .map function seems to be causing an early return from the called/subsidiary functions, and yet still continuing on inside the called/subsidiary functions after the early return happens.
Here is the code:
const db = require(`../../models`)
const findInDB_by_id = async params => {
console.log(`querying db`)
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({
_id: {
$in: params[table]._ids
}
})
}))
console.log('done querying the db')
// do stuff with records
return records
}
// call await findIndDB_by_id and do other stuff
// eventually return the response object
And here are the server logs
querying db
POST <route> <status code> 49.810 ms - 9 //<- and this is the appropriate response
done querying the db
... other stuff
When I the function is modified so that the map function doesn't return anything, (a) it doesn't query the database, and (b) doesn't return the express response object early. So by modifying this:
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({ // going to delete the `return` command here
_id: {
$in: params[table]._ids
}
})
}))
to this
const records = await Promise.all(Object.keys(params).map(function(table){
db[table].find({ // not returning this out of map
_id: {
$in: params[table]._ids
}
})
}))
the server logs change to:
querying db
done querying the db
... other stuff
POST <route> <status code> 49.810 ms - 9 // <-appropriate reponse
But then I'm not actually building my query, so the query response is empty. I'm experiencing this behavior with the anonymous map function being an arrow function of this format .map(table => (...)) as well.
Any ideas what's going on, why, or suggestions?
Your first version of your code is working as expected and the logs are as expected.
All async function return a promise. So findInDB_by_id() will always return a promise. In fact, they return a promise as soon as the first await inside the function is encountered as the calling code continues to run. The calling code itself needs to use await or .then() to get the resolved value from that promise.
Then, some time later, when you do a return someValue in that function, then someValue becomes the resolved value of that promise and that promise will resolve, allowing the calling code to be notified via await or .then() that the final result is now ready.
await only suspends execution of the async function that it is in. It does not cause the caller to be blocked at all. The caller still has to to deal with a promise returned from the async function.
The second version of your code just runs the db queries open loop with no control and no ability to collect results or process errors. This is often referred to as "fire and forget". The rest of your code continues to execute without regard for anything happening in those db queries. It's highly unlikely that the second version of code is correct. While there are a very few situations where "fire and forget" is appropriate, I will always want to at least log errors in such a situation, but since it appears you want results, this cannot be correct
You should try something like as when it encounter first async function it start executing rest of the code
let promiseArr = []
Object.keys(params).map(function(table){
promiseArr.push(db[table].find({
_id: {
$in: params[table]._ids
}
}))
})
let [records] = await Promise.all(promiseArr)
and if you still want to use map approach
await Promise.all(Object.keys(params).map(async function(table){
return await db[table].find({
_id: {
$in: params[table]._ids
}
})
})
)
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].
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
});
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.
I am trying to figure out how promises work in sails, and have been successful passing data from waterline queries via .then, but have not been able to utilize .spread. I am getting a function not defined error. Any suggestions how the first section of code can be improved to work?
//results in error
Promise.all([Xyz.find(), Abc.find()]).spread(function (someOtherResult, yetAnotherResult) {
console.log(someOtherResult)
}).catch(function (err) {
console.log(err);
})
The following work but would be either trickier to extract data from, or require excessively long nested .then clauses:
Promise.all([Xyz.find(), Abc.find()]).then(function (results) {
console.log(results[0][1]);
console.log(results[0].length);
})
Abc.find().then(function (foundAbcs) {
Promise.all(Xyz.find().then(function (foundXyzs) {
console.log(foundAbcs);
console.log(foundXyzs);
// additional syncranouse logic with Abc and Xyz
}))
})
Okay, very simple mistake, I didn't realize I needed:
var Promise = require('bluebird');
prior to module.exports in sails.js .11, problem solved.