Используйте Promise или Await в запросе Firebase - PullRequest
0 голосов
/ 03 марта 2020

Я пытаюсь выполнить запрос, который захватывает коллекцию местоположений. Затем необходимо проверить каждое местоположение по временной коллекции, чтобы убедиться, что оно еще не существует. Если он не существует, он входит в массив. Затем он перебирает массив и случайным образом получает три.

Вот мой код:

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)
            })

Проблема с этим текущим кодом в том, что журнал консоли будет выглядеть следующим образом 1 3 2, и я нужно 1 2 3. Я знаю, что мне нужно использовать обещание или ждать, но я все еще новичок в их использовании и не уверен, как его реализовать.

Может кто-нибудь показать мне, как использовать Promise или Await, чтобы мой код работал в правильном порядке?

Ответы [ 2 ]

3 голосов
/ 03 марта 2020

Будут полезны две идеи: (1) факторинг, чтобы вы могли видеть, что происходит, разрабатывать меньшие, тестируемые функции. (2) Promise.all(), чтобы выполнить каждое обещание, сгенерированное в al oop.

// 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;
}
1 голос
/ 03 марта 2020

Я не могу проверить следующий код, но не могли бы вы попробовать следующее.

Обратите внимание на async и 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];
  }
...