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
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 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
I'm playing with the Rick and Morty API and I want to get all of the universe's characters
into an array so I don't have to make more API calls to work the rest of my code.
The endpoint https://rickandmortyapi.com/api/character/ returns the results in pages, so
I have to use recursion to get all the data in one API call.
I can get it to spit out results into HTML but I can't seem to get a complete array of JSON objects.
I'm using some ideas from
Axios recursion for paginating an api with a cursor
I translated the concept for my problem, and I have it posted on my Codepen
This is the code:
async function populatePeople(info, universePeople){ // Retrieve the data from the API
let allPeople = []
let check = ''
try {
return await axios.get(info)
.then((res)=>{
// here the current page results is in res.data.results
for (let i=0; i < res.data.results.length; i++){
item.textContent = JSON.stringify(res.data.results[i])
allPeople.push(res.data.results[i])
}
if (res.data.info.next){
check = res.data.info.next
return allPeople.push(populatePeople(res.data.info.next, allPeople))
}
})
} catch (error) {
console.log(`Error: ${error}`)
} finally {
return allPeople
}
}
populatePeople(allCharacters)
.then(data => console.log(`Final data length: ${data.length}`))
Some sharp eyes and brains would be helpful.
It's probably something really simple and I'm just missing it.
The following line has problems:
return allPeople.push(populatePeople(res.data.info.next, allPeople))
Here you push a promise object into allPeople, and as .push() returns a number, you are returning a number, not allPeople.
Using a for loop to push individual items from one array to another is really a verbose way of copying an array. The loop is only needed for the HTML part.
Also, you are mixing .then() with await, which is making things complex. Just use await only. When using await, there is no need for recursion any more. Just replace the if with a loop:
while (info) {
....
info = res.data.info.next;
}
You never assign anything to universePeople. You can drop this parameter.
Instead of the plain for loop, you can use the for...of syntax.
As from res you only use the data property, use a variable for that property only.
So taking all that together, you get this:
async function populatePeople(info) {
let allPeople = [];
try {
while (info) {
let {data} = await axios.get(info);
for (let content of data.results) {
const item = document.createElement('li');
item.textContent = JSON.stringify(content);
denizens.append(item);
}
allPeople.push(...data.results);
info = data.info.next;
}
} catch (error) {
console.log(`Error: ${error}`)
} finally {
section.append(denizens);
return allPeople;
}
}
Here is working example for recursive function
async function getAllCharectersRecursively(URL,results){
try{
const {data} = await axios.get(URL);
// concat current page results
results =results.concat(data.results)
if(data.info.next){
// if there is next page call recursively
return await getAllCharectersRecursively(data.info.next,results)
}
else{
// at last page there is no next page so return collected results
return results
}
}
catch(e){
console.log(e)
}
}
async function main(){
let results = await getAllCharectersRecursively("https://rickandmortyapi.com/api/character/",[])
console.log(results.length)
}
main()
I hesitate to offer another answer because Trincot's analysis and answer is spot-on.
But I think a recursive answer here can be quite elegant. And as the question was tagged with "recursion", it seems worth presenting.
const populatePeople = async (url) => {
const {info: {next}, results} = await axios .get (url)
return [...results, ...(next ? await populatePeople (next) : [])]
}
populatePeople ('https://rickandmortyapi.com/api/character/')
// or wrap in an `async` main, or wait for global async...
.then (people => console .log (people .map (p => p .name)))
.catch (console .warn)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script>/* dummy */ const axios = {get: (url) => fetch (url) .then (r => r .json ())} </script>
This is only concerned with fetching the data. Adding it to your DOM should be a separate step, and it shouldn't be difficult.
Update: Explanation
A comment indicated that this is hard to parse. There are two things that I imagine might be tricky here:
First is the object destructuring in {info: {next}, results} = <...>. This is just a nice way to avoid using intermediate variables to calculate the ones we actually want to use.
The second is the spread syntax in return [...results, ...<more>]. This is a simpler way to build an array than using .concat or .push. (There's a similar feature for objects.)
Here's another version doing the same thing, but with some intermediate variables and an array concatenation instead. It does the same thing:
const populatePeople = async (url) => {
const response = await axios .get (url)
const next = response .info && response .info .next
const results = response .results || []
const subsequents = next ? await populatePeople (next) : []
return results .concat (subsequents)
}
I prefer the original version. But perhaps you would find this one more clear.
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 have a Cloud Function used to cross reference two lists and find values that match each other across the lists. The function seems to be working properly, however in the logs I keep seeing this Error serializing return value: TypeError: Converting circular structure to JSON . Here is the function...
exports.crossReferenceContacts = functions.database.ref('/cross-ref-contacts/{userId}').onWrite(event => {
if (event.data.previous.exists()) {
return null;
}
const userContacts = event.data.val();
const completionRef = event.data.adminRef.root.child('completed-cross-ref').child(userId);
const removalRef = event.data.ref;
var contactsVerifiedOnDatabase ={};
var matchedContacts= {};
var verifiedNumsRef = event.data.adminRef.root.child('verified-phone-numbers');
return verifiedNumsRef.once('value', function(snapshot) {
contactsVerifiedOnDatabase = snapshot.val();
for (key in userContacts) {
//checks if a value for this key exists in `contactsVerifiedOnDatabase`
//if key dioes exist then add the key:value pair to matchedContacts
};
removalRef.set(null); //remove the data at the node that triggered this onWrite function
completionRef.set(matchedContacts); //write the new data to the completion-node
});
});
I tried putting return in front of completionRef.set(matchedContacts); but that still gives me the error. Not sure what I am doing wrong and how to rid the error. Thanks for your help
I was having the exact same issue when returning multiple promises that were transactions on the Firebase database. At first I was calling:
return Promise.all(promises);
My promises object is an array that I'm using where I'm pushing all jobs that need to be executed by calling promises.push(<add job here>). I guess that this is an effective way of executing the jobs since now the jobs will run in parallel.
The cloud function worked but I was getting the exact same error you describe.
But, as Michael Bleigh suggested on his comment, adding then fixed the issue and I am no longer seeing that error:
return Promise.all(promises).then(() => {
return true;
}).catch(er => {
console.error('...', er);
});
If that doesn't fix your issue, maybe you need to convert your circular object to a JSON format. An example is written here, but I haven't tried that: https://stackoverflow.com/a/42950571/658323 (it's using the circular-json library).
UPDATE December 2017: It appears that in the newest Cloud Functions version, a cloud function will expect a return value (either a Promise or a value), so return; will cause the following error: Function returned undefined, expected Promise or value although the function will be executed. Therefore when you don't return a promise and you want the cloud function to finish, you can return a random value, e.g. return true;
Try:
return verifiedNumsRef.once('value').then(function(snapshot) {
contactsVerifiedOnDatabase = snapshot.val();
for (key in userContacts) {
//checks if a value for this key exists in `contactsVerifiedOnDatabase`
//if key dioes exist then add the key:value pair to matchedContacts
};
return Promise.all([
removalRef.set(null), //remove the data at the node that triggered this onWrite function
completionRef.set(matchedContacts)
]).then(_ => true);
});
I had the same error output with a pretty similar setup and couldn't figure out how to get rid of this error.
I'm not totally sure if every essence has been captured by the previous answers so I'm leaving you my solution, maybe it helps you.
Originally my code looked like this:
return emergencyNotificationInformation.once('value', (data) => {
...
return;
});
But after adding then and catch the error did go away.
return emergencyNotificationInformation.once('value')
.then((data) => {
...
return;
})
.catch((error) => {
...
return:
});
}
We fixed a similar issue with the same error by returning Promise.resolve() at the bottom of the chain, e.g.:
return event.data.ref.parent.child('subject').once('value')
.then(snapshot => {
console.log(snapshot.val());
Promise.resolve();
}).catch(error => {
console.error(error.toString());
});