Firebase запрос с вложенной коллекцией - PullRequest
0 голосов
/ 29 февраля 2020

У меня возникают трудности при извлечении вложенной коллекции, когда я запросил документ с помощью .where(). Я получаю сообщение об ошибке:

TypeError: collectionData.where(...).collection is not a function

Если я использую стандарт .doc(), он работает, .where() не работает.

hotels - это подколлекция каждого do c в основной коллекции. Предполагается, что hotelCollection передает извлеченные данные через класс для анализа и выполнения.

index. js

exports.hotels = functions.https.onRequest((req,res) => {
    cors(req, res, () => {
        const countryCode = req.url.replace('/', '').toUpperCase();
        const hotelCollection = collectionData.where('countryCode', '==', 'VN').collection('hotels');

        switch (req.method) {
            case 'GET':
                Hotels.list(hotelCollection, req, res);
                break;
            case 'POST':
                Hotels.create(hotelCollection, req, res);
                break;
            default:
                res.status(405).send({error: 'An error occurred!'});
                break;
        }
    })
});

hotel. js

let admin = require('firebase-admin');

class Hotels {

    static list(hotelCollection, req, res) {
        let hotelData = [];

        return hotelCollection.collection('hotels').get()
            .then(hotels => {
                hotels.forEach(hotel => {
                    hotelData.push(hotel.data());
                });
                return hotelData;
            })
            .then(hotelData => {
                return res.status(200).send(hotelData);
            })
            .catch(err => {
                return res.status(404).send('Error finding hotel for this country: ' + err);
            });
    }

    static create(hotelCollection, req, res) {
        return hotelCollection.add(req.body)
            .then(result => {
                return res.status(200).send('Hotel has been added!');
            })
            .catch(err => {
                return res.status(404).send('Error adding hotel for this country: ' + err);
            });
    }
}
module.exports = Hotels;

База данных enter image description here

1 Ответ

1 голос
/ 29 февраля 2020

В вашем классе Hotels, в методе create, hotelCollection должно быть CollectionReference, так как вы вызываете метод add().

На с другой стороны, в методе list, поскольку вы делаете hotelCollection.collection('hotels').get(), это означает, что hotelCollection будет DocumentReference (или hotelCollection равно admin.firestore(), что не похоже, дело в этом ...).

Итак, если вы хотите иметь одинаковую подпись для этих двух методов, вы должны передать CollectionReference, соответствующий вложенному набору hotels документа возвращается по вашему запросу.


Итак, сначала измените класс Hotels следующим образом:

class Hotels {

    static list(hotelCollection, req, res) {
        let hotelData = [];

        return hotelCollection.get()  // <-- !!! See change here
            .then(hotels => {
                hotels.forEach(hotel => {
                    hotelData.push(hotel.data());
                });
                return res.status(200).send(hotelData);  // !!! <-- and also here, we removed a then()
            })
            .catch(err => {
                return res.status(404).send('Error finding hotel for this country: ' + err);
            });
    }

    static create(hotelCollection, req, res) {
        return hotelCollection.add(req.body)
            .then(result => {
                return res.status(200).send('Hotel has been added!');
            })
            .catch(err => {
                return res.status(404).send('Error adding hotel for this country: ' + err);
            });
    }
}

Затем вызовите его следующим образом:

exports.hotels = functions.https.onRequest((req,res) => {
    cors(req, res, () => {

        const countryCode = req.url.replace('/', '').toUpperCase();

        const countryQuery = collectionData.where('countryCode', '==', 'VN');

        countryQuery.get()
        .then(querySnapshot => {
           const countryDocRef = querySnapshot.docs[0].ref;
           const hotelCollection = countryDocRef.collection('hotels');

           switch (req.method) {
              case 'GET':
                  Hotels.list(hotelCollection, req, res);
                  break;
              case 'POST':
                  Hotels.create(hotelCollection, req, res);
                  break;
              default:
                  res.status(405).send({error: 'An error occurred!'});
                  break;
           }

        });

    });
});

Сначала вы выполняете запрос, затем получаете первое QueryDocumentSnapshot из QuerySnapshot через свойство docs, затем получаете его DocumentReference и, наконец, получаете * 1039 документа * подколлекция, чтобы передать ее Hotels методам.

Обратите внимание, что приведенный выше код основан на двух предположениях:

  • Существует только один документ с заданным значением countryCode, следовательно, используется docs[0];
  • Переменная collectionData содержит коллекцию, показанную на скриншоте «База данных», т.е. в левой части скриншота.

Наконец, обратите внимание, что если вы хотите получить значение countryCode из URL-адреса запроса GET HTTPS (т. е. заменить жестко закодированное значение VN на значение переменной, переданное через параметры строки запроса GET), следует использовать req.query, см. https://flaviocopes.com/express-get-query-variables/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...