带子集合的Firebase查询

时间:2020-02-29 06:25:15

标签: javascript firebase google-cloud-firestore

使用.where()查询文档时,我很难提取子集合。我不断收到错误消息:

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

如果我使用标准的.doc()有效,则.where()不起作用。

hotels是主集合中每个文档的子集合。假设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 个答案:

答案 0 :(得分:1)

在您的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,最后获取文档的{{ 1}}子集合,以便将其传递给hotels方法。

请注意,以上代码基于两个假设:

  • 只有一个文档具有给定的Hotels值,因此使用countryCode;
  • docs[0]变量保存“数据库”屏幕截图中显示的集合,即屏幕截图左侧的集合。

最后,请注意,如果要从GET HTTPS请求的URL中获取collectionData的值(即,将硬编码的countryCode值替换为通过GET查询字符串传递的变量值)参数),则应使用VN,请参见https://flaviocopes.com/express-get-query-variables/