I am trying to implement a function in Express to return a list with data from a mongoose model. 'MiModelo' is the mongoose model created from a Schema.
//Get data in the DB
function getAllData()
{
var promesa = MiModelo.find().exec();
console.log(promesa);
console.log("---");
var miLista=[];
async = require('async');
async.parallel([function(){
promesa.then(function(datos)
{
datos.forEach(function(dato){
console.log("dato: " + dato.numero)
miLista.push(dato.numero);
});
});
}],function(){
console.log(miLista);
});
return miLista;
}
In the final console.log() I am able to get all 'numero' field values from the database but the return is empty when I call this function elsewhere. I know it is because it is asynchronous.
I have read the answer in this question: How to make a function wait until a callback has been called using node.js but I do not know how to adapt my function.
Any help is appreciated.
Thank you for your time and help.
The whole function can be simplified to a few lines:
async function getAllData() {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
const datos = await MiModelo.find().exec();
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
const miLista = datos.map(dato => dato.numero)
return miLista;
}
which you can then call like so:
const data = await getAllData()
// or
getAllData().then(data => console.log(data))
Related
I'm learning NodeJS and MongoDB. I dont know what is happening with this function.
getAllUsers = async () = {
let user;
let result = await new Connection().connect();
if (result.status == "ok")
{
user = await User.find();
}
return user;
};
If I make a console.log before return user, it works fine (just print an JSON array with all info of the collection)
The problem is when I call it from another file (in my case, the router). If I do this, I receive an empty json.
Why is this happening?
Thanks for your help!!
When calling your function getAllUsers, you need to add await in front of it since it is an async function.
For example,
var listUsers = await getAllUsers();
I'd like to:
Make a call to an API resource
Get back an array of records - [arr]
forEach over [arr] and perform some function - another aysnc call to an API
For each iteration, create an object that has elements of the original API call, and the subsequent call for each item
Save each object instance generated to Mongo
At the end of all required save operations, call the complete collection from Mongo
res.render that collection
I have code that looks like this:
//First API call to get [arr]
const results = await getlist();
//Iterate over [arr] and perform a request on each item
_.forEach(results, async function (result) {
//Seconday request for each item in [arr]
const record = await item(result.id).fetch();
//Combined doc from original result and secondary call for record
let doc = new DocModel({
item1: result.id,
item2: record.something,
});
//Save doc
const saveDoc = doc.save();
});
//Call for all docs
const allItems = await DocModel.find();
//Render all docs
res.render(`aView`, {
recordings: allItems,
});
The problem I am facing is that the render executes before the forEach has completed / has populated Mongo.
To try and work around this, I have tried to wrap the forEach block in a promise, and then .then res.render, but this seemed to have no effect.
What is the solution to ensure all function calls have completed before the render occurs?
I place two marks in following code. And i deleted the _.forEach function
mark1: Use normal for-loop to do it
mark2: use await here
//First API call to get [arr]
const results = await getlist();
// ########## mark1 ########## : Use normal for-loop to do it
for (const result of results) {
//Seconday request for each item in [arr]
const record = await item(result.id).fetch();
//Combined doc from original result and secondary call for record
let doc = new DocModel({
item1: result.id,
item2: record.something,
});
// ########## mark2 ########## : use await here
//Save doc
const saveDoc = await doc.save();
}
//Call for all docs
const allItems = await DocModel.find();
//Render all docs
res.render(`aView`, {
recordings: allItems,
});
You can't use async await inside forEach. Instead you need to use for...of loop.
Another best solution is to use Promise.all
Promise.all
await Promise.all(_.map(results,async result => {
... existing code
});
I am developing a business manager web app in React with Firebase back-end. I am also coding a local API to simplify Firebase functions. I created this method, which loads data from a Firebase collection and returns an array of documents.
getDocuments(collection) {
var documents = [];
firebase.firestore().collection(collection).get().then(snapshot => {
snapshot.forEach(doc => {
documents.push(doc);
});
}).then(() => {
return documents;
})
}
However, when I call the method and assign it to a variable which I later print to the console, it says undefined.
var employees = getDocuments("employees");
console.log(employees);
What I want to do is to use .then() after calling the method to print the already loaded data to the console. Something like this:
var employees = getDocuments("employees").then(response => {
console.log(response);
})
Any help would be appreciated. Thank you.
Your getDocuments function seems to be unnecessarily complicated. This:
getDocuments(collection) {
return firebase.firestore().collection(collection).get().then(snapshot=>snapshot.docs)
}
yields exactly the same intended result (an Array of docs wrapped in a promise) as your function but performs faster since it skips looping through all the documents in the snapshot https://firebase.google.com/docs/reference/js/firebase.firestore.QuerySnapshot#docs
Afterwards just extract the value from the Promise returned by this function in your preferred way:
Option 1 (async/await)
let employees= await getDocuments('employees')
console.log(employees)
Option 2 (chaining)
let employees =[]
getDocuments('employees').then(response => {
employees=response
console.log(employees)
})
Explanation
When you are doing this:
var employees = getDocuments("employees").then(response => {
console.log(response);
})
you aren't receiving any value from getDocuments since you didn't return anything in the first place.
getDocuments(collection) {
var documents = [];
firebase.firestore().collection(collection).get().then(snapshot => {
snapshot.forEach(doc => {
documents.push(doc);
});
}).then(() => {
return documents; <-- this is returning the value of documents to the parent scope which is 'getDocuments', since the 'then' is related to the 'get' function
})
}
You should assign employees in the then like this
var employees = [];
getDocuments("employees").then(response => {
employees = response;
console.log(response);
})
Or if you are in an asynchronous function, you could go for something like this
var employees = await getDocuments("employees");
console.log(employees);
But the await keyword has to be done in an async function
This might be a bit of a beginner question, but I can't figure this out:
I'm doing an asyncronous database call in which I want to get an object from the database and asign this object to the window object (window.naamID).
Next I want to run a function where I use the object assinged to the window object (making it global) and use it as a database query (.where("Vraagsteller", "==", naamID)).
The problem, of course, is that the second function starts running before the first function has fnished (because of it's asyncronous nature).
I wanted to overcome this problem by wrapping the second function in a syncronous function and await the first function.
This doesn't seem the work. The console says the object asigned to the window object is undefined.
This is the code:
function constructAuthMenu(){
auth.onAuthStateChanged(User =>{
const userRef = db.collection("Vitaminders")
.doc(User.uid);
userRef.get()
.then(function(doc) {
const naamID = doc.data().Gebruikersnaam;
const ID = doc.data().ID
const naam = naamID.replace(ID, "")
const profilePic = doc.data().Profielfoto
window.naamID = naamID
});
});
};
constructAuthMenu()
async function getNewReactions(){
await constructAuthMenu()
db.collectionGroup("Reactions")
.where("Vraagsteller", "==", naamID)
.where("New", "==",
"Yes").get().then(querySnapshot => {
querySnapshot.forEach(doc => {
*Do stuff*
});
});
What am I doing wrong? Or doesn't async await work like this?
If constructMenuFunction actually exists elsewhere in your code, and returns a Promise, then your problem is that you're missing parentheses on your function call: await constructMenuFunction();
If constructMenuFunction does not exist elsewhere in your code, and the first function preceding the async function is actually what you wish to invoke, your problem is that the first function does not return a Promise and your async function invokes the wrong method and without parentheses.
async function constructAuthMenu() {
return await auth.onAuthStateChanged(async User => {
try {
const userRef = db.collection("Vitaminders").doc(User.uid);
const doc = await userRef.get();
const naamID = doc.data().Gebruikersnaam;
const ID = doc.data().ID;
const naam = naamID.replace(ID, "");
const profilePic = doc.data().Profielfoto;
return naamID;
} catch(err) {
console.error(err);
}
});
};
Thank you in advance for anyone that reads this. I really appreciate any and all help.
so this is my first app personal app. I have setup a DB in Atlas on mongodb.com and I can write to it with out an issue. But when my app tries and pull from my db I can get it to print to console. But I am able to assign the data to any variable to use anywhere else in my my app.
here is my code that works to print to the console. But not sure what setup or package I am missing so i can store it as a local variable. I am using a callback function to return the api call and the console print out works. just dont know what to do next
function getTerms() {
let allTerms = []
termAdd.find({}, '_id', (err, term) => {
term.map((term) => {
allTerms.push(term)
// if I understand Push() correctly this should store my output to allTerms.
});
//this works to print out to console in JSON.
console.log(allTerms, 'getTerms')
return allTerms;
});
};
if (res.statusCode === 200) {
//callback function to return the console from the function
getTerms()
// when i do a let foo = getTerms() it will return undefined
//so I am really dont understand how to assign the return from
//the function to a variable.
//How do I assign this console output to variable to use for output
console.log('200 statusCode')
};
//Random Number Generator
let ranNum = Math.floor((Math.random() * 10) + 1);
console.log('random number = ',ranNum);
res.render('fs', {
flashCard : 'Test Card',
items: ranNum
});
});
I have the full code on GitHub if that would help I can link to this project.
Should I be using a delay in anyway. I was given a suggestion. But I did not understand what I was reading.
Before anything, please abstain of pushing your .env file to Github or sharing anything in it publicly.
You separated the functionality of getting terms into its own function, which is good:
// Get function for all items in mongodb
function allItems(all) {
let allTerms = []
termAdd.find({}, 'term', (err, term) => {
term.map((term) => {
allTerms.push(term)
});
//this works to print out to console.
console.log(allTerms, 'function allTerms')
//Question is how to I get this JSON to save to a VAR or be passed to another function
});
};
First of all I would rename it to getAllTerms, since it's what it does. And it seems the all parameter is not necessary.
**
Anyway, usually, what you would do is simply return the allTerms variable as such:
// Get function for all items in mongodb
function getAllTerms() {
let allTerms = []
termAdd.find({}, 'term', (err, term) => {
term.map((term) => {
allTerms.push(term)
});
//this works to print out to console.
console.log(allTerms, 'function allTerms')
//Question is how to I get this JSON to save to a VAR or be passed to another function
});
return allTerms
}
However, this wouldn't work because since you are making a call to a database, it might take some time for the database to get the terms; in this case, allTerms might return an empty array, [].
What you have to do is wait for the database to return the terms, push them into the allTerms array, and finally return it.
// Get function for all items in mongodb
async function getAllTerms() {
let allTerms = []
const fetchedTerms = await termAdd.find({}, 'term')
fetchedTerms.forEach(fetchedTerm => allTerms.push(fetchedTerm))
return allTerms
}
If you don't know what async and await are, no worries, here is a good article explaining the why and when to use them.
If you still have any questions, let me know.
Using Async/Await the code above can be optimized as the code below:
`
async function getTerms() {
//using async/await
try{
const terms = await termAdd.find({}, '_id')
const allTerms = terms.map((term)=>term)
// return allTerms here
return allTerms
}catch(err){
throw err
}
}
`
for more insight on Async/Await here is a good read