【问题标题】:Firebase query with subcollection带有子集合的 Firebase 查询
【发布时间】:2020-02-29 06:25:15
【问题描述】:

当我使用.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;

数据库

【问题讨论】:

  • 错误消息告诉您where() 不返回具有称为collection() 的方法的对象。它返回一个尚未执行的 Query 对象。我不清楚你希望这段代码实际做什么,因为我们看不到数据库中的数据,我们看不到 Hotel 上的函数实现,我们不知道应该做什么是它应该产生的响应。
  • @DougStevenson 我已经用更多上下文更新了这个问题

标签: javascript firebase google-cloud-firestore


【解决方案1】:

在您的Hotels 类中,在create 方法中,hotelCollection 应该是CollectionReference,因为您调用了add() 方法。

另一方面,在list方法中,既然你做了hotelCollection.collection('hotels').get(),这意味着hotelCollection应该是一个DocumentReference(或者hotelCollection等于admin.firestore(),这似乎不是就是这样……)。

因此,如果您希望这两种方法具有相同的签名,则应传递与查询返回的文档的hotels 子集合对应的CollectionReference


所以,首先,修改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;
           }

        });

    });
});

你先执行查询,然后通过docs属性得到QuerySnapshot的第一个QueryDocumentSnapshot,然后得到它的DocumentReference,最后得到文档的hotels子集合,为了将其传递给 Hotels 方法。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    • 2020-10-10
    相关资源
    最近更新 更多