Reputation: 1141
I am trying to run a query that grabs a collection of locations. It then needs to check each location against a temp collection to make sure it does not already exist. If it doesn't exists it goes into the array. Next it loops through the array and randomly grabs three.
Here is my code:
let locations = []
let getLocations = db.collection('locations')
.where('area', '==', 'central')
.get().then(snapshot => {
snapshot.forEach(doc => {
let loc = doc.data()
loc.id = doc.id
console.log('1')
let locationsplayedRef = db.collection('locationsplayed')
locationsplayedRef = locationsplayedRef.where('location_id', '==', loc.id)
locationsplayedRef.get().then(snapshot => {
// make sure the location is not already in the db
if (snapshot.empty) {
// only grab activated locations
if(!loc.deactivated)
locations.push(loc)
}
console.log('2 ', locations)
})
})
}).then(() => {
for (let i = locations.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[locations[i], locations[j]] = [locations[j], locations[i]];
}
let third = locations[0];
let [first, second] = locations.filter(l => !l.restaurant).slice(1);
let selectedLocations = [first, second, third];
console.log('3 ', selectedLocations)
})
The problem with this current code is the console log will look like this 1 3 2 and I need 1 2 3. I know I need to use a promise or await but I am still new to using these and am not sure how to implement it.
Could someone show me how to use either a Promise or Await so my code runs in the proper order?
Upvotes: 0
Views: 61
Reputation: 62686
Two ideas will be useful: (1) factoring, so you can see what's going on, develop smaller, testable functions. (2) Promise.all()
, to perform every promise generated in a loop.
// return a promise that resolves to the passed loc or null if the loc is played
function isLocationPlayed(loc) {
let locationsplayedRef = db.collection('locationsplayed')
locationsplayedRef = locationsplayedRef.where('location_id', '==', loc.id)
return locationsplayedRef.get().then(snapshot => {
// make sure the location is not already in the db
return (snapshot.empty && !loc.deactivated) ? loc : null
})
}
// return a promise that resolves to an array of locations that have been played
playedLocations() {
let locations = []
let getLocations = db.collection('locations').where('area', '==', 'central')
return getLocations.get().then(snapshot => {
// build an array of promises to check isLocationPlayed
let promises = snapshot.docs.map(doc => {
let loc = doc.data()
return isLocationPlayed(loc)
})
// resolve when all of the passed promises are resolved
return Promise.all(promises)
}).then(results => {
return results.filter(e => e) // remove nulls
})
}
playedLocations().then(locations => {
console.log(fyShuffle(locations))
})
// shuffle an array using Fisher Yates
function fyShuffle(a) {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
Upvotes: 3
Reputation: 871
I'm unable to test the following code, But could you try the following.
Take note of async
and await
async someFunction() {
const locations = [];
await db
.collection("locations")
.where("area", "==", "central")
.get()
.then(async snapshot => {
const docs = snapshot.docs;
// Must use for of loop here
for (const doc of docs) {
const loc = doc.data();
await db
.collection("locationsplayed")
.where("location_id", "==", loc.id)
.get()
.then(snapshot => {
// make sure the location is not already in the db
if (snapshot.empty) {
// only grab activated locations
if (!loc.deactivated) {
locations.push(loc);
}
}
});
}
});
for (let i = locations.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[locations[i], locations[j]] = [locations[j], locations[i]];
}
let third = locations[0];
let [first, second] = locations.filter(l => !l.restaurant).slice(1);
let selectedLocations = [first, second, third];
}
Upvotes: 1