Get array from function - javascript

I have tried to get the array I can log inside the function to be used outside. I’m using sapper. Have been stuck with this for multiple hours now, so it was time to reach out to the community!
let dvd = [];
let artistName = [];
let searchString = [];
onMount(async () => {
const res = await fetch(`artists/all`);
const data = await res.json();
const newdata = data.map(x => {
if (x.titles.length > 0) {
dvd.push(x.titles[0].graphics.dvd)
artistName.push(x.titles[0])
}
})
})
let searchTerm = '';
async function getData() {
searchString.push(artistName.filter(d => d.artistName === searchTerm));
console.log(searchString)
}

If I understand the question correctly, your issue is that the updated value of searchString is not being applied to the DOM. This is due to how Svelte's reactivity works. From the tutorial:
Because Svelte's reactivity is triggered by assignments, using array methods like push and splice won't automatically cause updates.
You should update getData to assign to searchString instead of calling push.
async function getData() {
searchString = [...searchString, artistName.filter(d => d.artistName === searchTerm)];
console.log(searchString)
}

Related

how to deal with firebase onsnapshot as an object or array?

im doing orders onsnapshot from firebase but im confused how to deal with it, I get an [] when I log it out but when I logout the type of orders it says object,
I'm trying to add the id of each order and place it inside the array orders along with the existing data but its not working , if I
console.log(orders[0]) I get undefined and if I treat it as an object orders['0'] i also get undefined.
here is the code:
im using vuejs mounted
async mounted() {
let id = [];
let orders = [];
await db.collection("orders").onSnapshot(doc => {
doc.docs.forEach(x => {
id.push(x.id);
orders.push(x.data());
});
});
for (order in orders) {
let i = 0;
order.id = id[i];
i++
}
console.log(orders);
}}
the result of this code is the same orders array without any change at all.
Data is loaded from Firestore asynchronously. While that is happening, your main code continues to execute, so that the user can continue to use the app.
What this means in practice is that in your code the console.log(orders) is executed before any of the orders.push(x.data()) is ever run.
The solution is pretty simple: any code that needs the data from the database, needs to be inside the callback that is called with the data:
async mounted() {
let id = [];
let orders = [];
db.collection("orders").onSnapshot(doc => {
doc.docs.forEach(x => {
id.push(x.id);
orders.push(x.data());
});
for (order in orders) {
let i = 0;
order.id = id[i];
i++
}
console.log(orders);
});
}
}
Alternatively, you can use async and await to handle the asynchronicity, but in that case you should use get instead of onSnapshot and not use a callback:
async mounted() {
let id = [];
let orders = [];
const snapshot = await db.collection("orders").get();
snapshot.docs.forEach(x => {
id.push(x.id);
orders.push(x.data());
});
for (order in orders) {
let i = 0;
order.id = id[i];
i++
}
console.log(orders);
}
You should check first, returning snap is either object or array. Generally I found it return object. Hence you should do like.
mounted = async () => {
let id = [];
let orders = [];
db.collection("orders").on("value", async snapshot => {
let ordersData = snapshot.val();
if (ordersData !== null) {
Object.values(ordersData).map(item => {
orders = [...orders, item.data]; //map according to your data
});
}
console.log("orders===>", orders);
});
};

How to add MySQL query results from a loop in Nodejs?

Essentially, I have an object with string keys and values (ex. {"michigan":"minnesota"}). I'm trying to loop through all of these key value pairs and make a query from my database, and add the result to a list, which will then be what is returned to the front end.
var return_list = []
Object.keys(obj).forEach(function(key){
const state1 = key;
const state2 = obj[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
db.query(sql_select,[state1,state2], (err,result) => {
return_list.push(result);
});
})
This is what I have in simplest terms, and would like to send return_list back to the front end. The problem I'm running into is I can console.log the result within db.query call, but I can't push the result to the list or call it anywhere outside of the query. I'm fairly new to both front end and back end development, so any possible ideas would definitely be helpful!
The problem is that the forEach returns void.
So you can't wait for the asynchronous code to run before you return it.
When we're dealing with an array of promises such as db queries ( like in your case ) or API calls, we should wait for every one of them to be executed.
That's when we use the Promise.all
Try doing it like this:
const queryResults = await Promise.all(
Object.keys(obj).map(async (key) => {
const state1 = key;
const state2 = obj[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
return new Promise((resolve, reject) =>
db.query(sql_select,[state1,state2], (err, result) => {
if (err)
return reject(err)
else
return resolve(result)
})
)
})
)
console.log('queryResults', queryResults)
// now you give this queryResults back to your FE
Small tips for your fresh start:
never use var, try always use const or if needed, let.
try always use arrow functions ( () => {...} ) instead of regular functions ( function () {...} ), It's hard to predict which scope this last one is using
The issue is because the database transaction is not instant, so you need to use either promises or async-await.
Using async await would be something like this (untested),
async function get_return_list () {
var return_list = []
Object.keys(obj).forEach(function(key){
const state1 = key;
const state2 = obj[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
await db.query(sql_select,[state1,state2], (err,result) => {
return_list.push(result);
});
})
return return_list
}
see for more detail: https://eloquentjavascript.net/11_async.html
First, make sure you are working with mysql2 from npm. Which provides async method of mysql.
Second, Note that when you query SELECT, you don't get the "real" result in first. Suppose you get result, then, the "real" results are held in result[0].
(async () => {
const promiseArr = [];
for (const key of Object.keys(yourOBJ)) {
const state1 = key;
const state2 = yourOBJ[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
promiseArr.push(db.query(sql_select, [state1, state2]));
}
let results;
try {
results = await Promise.all(promiseArr);
} catch (e) {
throw '...';
}
const return_list = results.reduce((finalArray, item) => {
finalArray = [
...finalArray,
...item[0],
]
}, []);
})();

Do you know how I can use async await withing a map function to change a variable in every loop?

Do you know how I can make sure that the value of "intentid" change for every loop within the map function? The wanted result is that intentid changes its value for every loop, so that a new value is sent to "someOtherAsyncApiFunction(someinnerfunction())". I need to use async/await, because "intentid2" calls an API.
let someobject = {1: {name: "Question"}, 2: {name: "Tipp"}, 3:{name: "Question"}}
intentid = "";
const someFunction = () => {
Object.keys(someobject).map(async (key,index) =>{
if (someobject[key].name === "Question") {
const someinnerfunction = () => {
let followupintent = intentid;
return followupintent
}
let intentid2 = await someOtherAsyncApiFunction(someinnerfunction())
intentid = intentid2
console.log(intentid)
}}
)
}
someFunction()
When you use an asnyc mapper function you will get an array of promises.
In order to resolve them, you could use Promise.all()
const result = await Promise.all(values.map(async x => doSomething(x)))

Store and update a stored Object

Im trying to store an object in AsyncStorage then retrieve it and merge it with the current one and save it again, thus keeping and updated object at all time. Im really struggling to understand the way you are supposed to store and manipulate this, any suggestions ? this is done in component will mount when the component and app loads ps I only manage to make a new array element with all the object
retrieve method
_retrieveObj = async () => {
try {
const value = await AsyncStorage.getItem('OBJECT');
if (value !== null) {
return JSON.parse(value);
}
return [];
} catch (error) {
// Error retrieving data
}
};
store method
_storeObj = async (obj) => {
let numberArray = [];
try {
let storedNumbers = await AsyncStorage.getItem('OBJECT');
if (storedNumbers !== null) {
numberArray = JSON.parse(storedNumbers);
}
numberArray.push(obj)
await AsyncStorage.setItem('OBJECT', JSON.stringify(numberArray));
} catch (error) {
console.log(error)
}
};
call within Component
_UpdateAndSave = async (objToDisplay) => {
const storedObj = await this._retrieveObj();
if (storedObj !== objToDisplay) {
const obj = this._merge(storedObj ,objToDisplay);
const objToSave = JSON.stringify(obj);
this._storeObj(objToSave);
}
method to merge objects (found online)
_merge = (a, b) => {
let c = {};
for(let idx in a) {
c[idx] = a[idx];
}
for(let idx in b) {
c[idx] = b[idx];
}
return c;
};
Thanks
The reason you are getting an array is because you are saving an array of objectsin your _storeObj function. It looks like you already merge the existing and new objects into one, so you simply have to save the result of the merge. You shouldn't need your _storeObj function.
_UpdateAndSave = async (objToDisplay) => {
const storedObj = await this._retrieveObj();
if (storedObj !== objToDisplay) {
const obj = this._merge(storedObj ,objToDisplay);
const objToSave = JSON.stringify(obj);
await AsyncStorage.setItem('OBJECT', objToSave);
}

Unable to receive proper data from the promise function

I am trying to scrap wikipedia page to fetch list of airlines by first scrapping first page and then going to each individual page of airline to get the website url. I have divided the code in two functions. One to scrap main page and get a new url, and second function to scrap another page from the created url to get the website name from that page. I have used request-promise module for getting the html and then cheerio to parse the data.
export async function getAirlinesWebsites(req,res) {
let response = await request(options_mainpage);
console.log(`Data`);
let $ = cheerio.load(response);
console.log('Response got');
$('tr').each((i,e)=>{
let children = '';
console.log('inside function ', i);
if($(e).children('td').children('a').attr('class') !== 'new') {
children = $(e).children('td').children('a').attr('href');
let wiki_url = 'https://en.wikipedia.org' + children;
console.log(`wiki_url = ${wiki_url}`);
let airline_url = getAirlineUrl(wiki_url);
console.log(`airline_url = ${airline_url}`);
}
})
And then the getAirlineUrl() function will parse another page based on the provided url.
async function getAirlineUrl(url){
const wiki_child_options = {
url : url,
headers : headers
}
let child_response = await request(wiki_child_options);
let $ = cheerio.load(child_response);
let answer = $('.infobox.vcard').children('tbody').children('tr').children('td').children('span.url').text();
return answer;
})
However when I console log the answer variable in the parent function, I get a [object Promise] value instead of a String. How do I resolve this issue?
Async function return promise.In case of that,you need to use then to get resolved response or use await.
This should work if other part of your code is ok.
export async function getAirlinesWebsites(req, res) {
let response = await request(options_mainpage);
console.log(`Data`);
let $ = cheerio.load(response);
console.log("Response got");
$("tr").each(async (i, e) => {
let children = "";
console.log("inside function ", i);
if ($(e).children("td").children("a").attr("class") !== "new") {
children = $(e).children("td").children("a").attr("href");
let wiki_url = "https://en.wikipedia.org" + children;
console.log(`wiki_url = ${wiki_url}`);
let airline_url = await getAirlineUrl(wiki_url);
console.log(`airline_url = ${airline_url}`);
}
});
}
Since your getAirlineUrl function returns a promise, you need to await that promise. You can't have await nested inside of the .each callback because the callback is not an async function, and if it was it wouldn't work still. The best fix is the avoid using .each and just use a loop.
export async function getAirlinesWebsites(req,res) {
let response = await request(options_mainpage);
console.log(`Data`);
let $ = cheerio.load(response);
console.log('Response got');
for (const [i, e] of Array.from($('tr')).entries()) {
let children = '';
console.log('inside function ', i);
if($(e).children('td').children('a').attr('class') !== 'new') {
children = $(e).children('td').children('a').attr('href');
let wiki_url = 'https://en.wikipedia.org' + children;
console.log(`wiki_url = ${wiki_url}`);
let airline_url = await getAirlineUrl(wiki_url);
console.log(`airline_url = ${airline_url}`);
}
}
}

Categories

Resources