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();
Related
Having this code:
const fs = require('fs')
const file = 'books.json';
class Book{
constructor(code) {
this._code = code;
}
get code() {
return this._code;
}
set code(value) {
this._code = value;
}
}
async function writeBooks(){
const data = JSON.stringify([new Book('c1'), new Book('c2')]);
await fs.promises.writeFile(file, data, 'utf8');
}
async function getBook(code){
try{
const data = await fs.promises.readFile(file);
const array = JSON.parse(data);
return array.find(b => b.code === code);
} catch (err){
console.log(err)
}
}
writeBooks();
getBook('c1').then(b => console.log(b));
I am getting undefined (instead of the expecting book object).
How to get the object (the above problem)
If async function always returns promise, how can I then return object for the client, instead of him having to call then() from the getBook(code)?
do I need to await for the fs.promises.writeFile()? as I am doing in writeBooks()? As fas as I understand the async/await now, is that the return value from await function is the data or error. But since the writeFile() does not returns anything, or error at most (as opposed to readFile()) why would I want to await for no data?
Actually the root of problem is not about async/awaits or promises. The problem is trying to write an array to a json file. If you write your json data like the code snippet below (as a key-value pair), your problem is solved.
{"1": [new Book('c1').code, new Book('c2').code]} //as a key-value pair
const fs = require('fs')
const file = 'books.json';
class Book{
constructor(code) {
this._code = code;
}
get code() {
return this._code;
}
set code(value) {
this._code = value;
}
}
async function writeBooks(){
const data = JSON.stringify({"1": [new Book('c1').code, new Book('c2').code]});
await fs.promises.writeFile(file, data, 'utf8');
}
async function getBook(code){
try{
const data = await fs.promises.readFile(file);
const dataOnJsonFile = JSON.parse(data);
return dataOnJsonFile["1"];
} catch (err){
console.log(err)
}
}
writeBooks();
getBook('c1').then(b => console.log(b));
The above problem is that the Books returned from JSON.parse have only data, not methods, and thus I cannot get the code via get code(){}, but only as public parameter of class Book as book._code, which however breaks encapsulation (convetion is that _[propery] is private, and there should be appropriate getters/setters). So I made the properties public (and broke encapsulation), because I still don't know, how to assign methods to object created from JSON.
No, the result of async is always Promise. You cannot unwrap it inside async, the client will always have to unwrap it. (so await fs.promises.WriteFile() will unwrap it, but then immediately wrap it back, before async function returns.
as explained above.
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
I have an function using axios where I am deleting multiple records based on the number of ids returned for a specific user.
async function DeleteAllRecords (emailAddress) {
try {
var accessToken = await setup.getAccessToken(emailAddress);
var userId = await user.getUserId(emailAddress);
var recordIds = await getAllRecordID(emailAddress);
console.log(`Deleting all records for `+emailAddress+``);
for (const rId of recordIds) {
const response = await axios.delete(`${process.env.API_URL}/`+userId+`/records/`+recordIds+``, {'headers': {Authorization: 'Bearer '+accessToken+''}});
}
return response;
}
catch(e) {
console.error(``+emailAddress+` produced the Record Delete Error = ` + e);
}
}
This isn't working, and I'm unsure why. I would like to see the response for each axios.delete call, but I'm not sure how to get that. Currently its returning as response undefined.
Why your code didn't work:
const response is declared inside the loop scope, and is not accessible out of this closure.
Even if it was defined before the loop (using let const), and assigned inside the loop, you would still be able to return only the last response.
You can push each response to an array (responses), and return the array:
async function DeleteAllRecords (emailAddress) {
try {
var accessToken = await setup.getAccessToken(emailAddress);
var userId = await user.getUserId(emailAddress);
var recordIds = await getAllRecordID(emailAddress);
console.log(`Deleting all records for `+emailAddress+``);
const responses = [];
for (const rId of recordIds) {
const response = await axios.delete(`${process.env.API_URL}/`+userId+`/records/`+recordIds+``, {'headers': {Authorization: 'Bearer '+accessToken+''}});
responses.push(response);
}
return responses;
}
catch(e) {
console.error(``+emailAddress+` produced the Record Delete Error = ` + e);
}
}
However, in this case multiple parallel requests would be better, since you don't actually need to delete one by one. I would use Array.map() to iterate the recordIds array, and return a promise for each one, then wait for all responses using Promise.all(), which would also return an array of responses:
async function DeleteAllRecords (emailAddress) {
try {
var accessToken = await setup.getAccessToken(emailAddress);
var userId = await user.getUserId(emailAddress);
var recordIds = await getAllRecordID(emailAddress);
console.log(`Deleting all records for `+emailAddress+``);
return Promise.all(recordIds.map(rId => axios.delete(`${process.env.API_URL}/`+userId+`/records/`+recordIds+``, {'headers': {Authorization: 'Bearer '+accessToken+''}})));
}
catch(e) {
console.error(``+emailAddress+` produced the Record Delete Error = ` + e);
}
}
This isn't working, and I'm unsure why. I would like to see the response for each axios.delete call, but I'm not sure how to get that. Currently its returning as response undefined.
There are several issues in your code:
const response declared within loop block, but you try to return it after the loop. const and let are strictly block scoped, thus by referring to response after the loop block basically tells JS to return an undefined variable.
You write several times to response. If the issue above wasnt in place, it would still not work correctly, since you only would end up with the response of the last loop run. Here you'd have to collect the response from all runs, e.g. into a list.
I'm new to NodeJS and I get some difficulties with its asynchronous nature.
I'm requesting some data using a async function. My second function is used to retrieve an ID while knowing the name (both info are stored in the data returned by the first function).
Everytime I get the 'Found it' in the console, but the return is executed before the loop is over and I get an 'undefined'.
Should I use a callback or use async & await ? Even after lot of research about async & await and callbacks I can't figure a way to make it work !
async function getCustomers() {
try {
var customers = await axios({
//Query parameters
});
return customers;
}
catch (error) {
console.log(error);
}
}
function getCustomerId(customerName){
var customerId = null;
getCustomers().then(function(response){
for (const i of response.data){
console.log(i['name']);
if(i['name'] == customerName){
console.log('Found it !'); //This got displayed in the console
customerId = i['id'];
return customerId; //This never return the desired value
}
}
});
}
console.log(getCustomerId('abcd'));
Thanks for any help provided !
You're printing the output of getCustomerId, but it doesn't return anything.
Try returning the Promise with:
return getCustomers().then(function(response) {...});
And then, instead of:
console.log(getCustomerId('abcd'));
You should try:
getCustomerId('abcd').then(function(id) {console.log(id);})
So that you are sure that the Promise is resolved before trying to display its output
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))