javascript - 优化在 Firebase Firestore 中检索按另一个集合分组的数据

标签 javascript firebase promise google-cloud-firestore

我的 Firestore 数据库中有两个集合,相当于:

// ItemCategories collection
{
    id_category_1: {
        name: 'Category 1',
    },
    id_category_2: {
        name: 'Category 2',
    },
    id_category_3: {
        name: 'Category 3',
    },
    // ...
}

// Items collection
{
    id_item_1: {
        CategoryId: 'id_category_1',
        name: 'Item 1',
    },
    id_item_2: {
        CategoryId: 'id_category_1',
        name: 'Item 2',
    },
    id_item_3: {
        CategoryId: 'id_category_3',
        name: 'Item 3',
    },
    id_item_4: {
        CategoryId: 'id_category_2',
        name: 'Item 4',
    },
    // ...
}

我想检索并格式化我的项目以按类别分隔,如下所示:

const ItemList = {
    'Category 1': [
        {
            id: 'id_item_1',
            CategoryId: 'id_category_1',
            name: 'Item 1',
        },
        {
            id: 'id_item_2',
            CategoryId: 'id_category_1',
            name: 'Item 2',
        },
    ],
    'Category 2': [
        {
            id: 'id_item_4',
            CategoryId: 'id_category_2',
            name: 'Item 4',
        },
    ],
    'Category 3': [
        {
            id: 'id_item_3',
            CategoryId: 'id_category_3',
            name: 'Item 3',
        },
    ],
};

我目前正在处理一堆 Promise:

// Function to retrieve Items for a given CategoryId
const getItemsByCategory = async CategoryId => {
    const Items = await new Promise(resolve => {
        firebase
            .firestore()
            .collection('items')
            .where('CategoryId', '==', CategoryId)
            .orderBy('name', 'ASC')
            .onSnapshot(querySnapshot => {
                const values = [];
                querySnapshot.forEach(doc => {
                    values.push({
                        ...doc.data(),
                        key: doc.id,
                    });
                });
                resolve(values);
            });
    });
    return Items;
};

// Function to actually get all the items, formatted as wanted
export const getItemList = () => {
    return dispatch => { // I'm in a Redux Action
        const Items = {};

        firebase
            .firestore()
            .collection('itemCategories')
            .orderBy('name', 'ASC')
            .get() // Categories can't be changed
            .then(querySnapshot => {
                const Promises = [];
                querySnapshot.forEach(doc => {
                    const category = doc.data().name;

                    const P = new Promise(resolve => {
                        getItemsByCategory(doc.id).then(values => {
                            const result = {
                                category,
                                values,
                            };
                            resolve(result);
                        });
                    });

                    Promises.push(P);
                });

                Promise.all(Promises).then(values => {
                    values.forEach(v => {
                        Items[v.category] = v.values;
                    });

                    // Here I have the formatted items
                    console.log(Items); 
                    //dispatch(setItemList(Items)); // Redux stuff
                });
            });
    }
};

这段代码可以工作,但我觉得应该有办法优化它。我至少可以看到两个问题:

  • 此代码进行(N+1) Firestore 调用(其中 N 是类别数)。由于 Firebase 对每次调用收费,因此我看不到这种扩展。

  • 我们必须等待 N 个 promise 才能实际显示数据;如果类别数量增长太多,执行时间可能会成为问题。

还有比我得到的更好的解决方案吗?

最佳答案

As Firebase charges every call, I can't see this scaling.

Firestore 不会根据“通话”收费。它按读取的文档数量和传输的数据量收费。如果您需要阅读所有类别,那么您只需支付阅读该馆藏的一些文档的费用。无论您花费多少次调用来读取这些文档(异常(exception)情况是返回 0 个结果的查询仍会产生一次读取)。

实际上,等待 1 个返回 N 个文档的查询与等待 N 个返回 1 个文档的查询之间并没有太大区别。不管怎样,你仍然只是在等待 N 个文档。借助 Firestore,所有查询都可以很好地扩展。限制因素始终取决于收到的文档数量,而不是查询数量。您的代码将主要花费时间等待结果传输。当然,内存中可以保存的内容数量有一个实际上限,但 Promise 的数量不会有什么大不了的。

除此之外,我不明白您为什么在 getItemsByCategory 中使用 onSnapshot。似乎您只想使用 get() 而不是在监听器中仅接收一个结果。这样你的代码就会简单得多。

关于javascript - 优化在 Firebase Firestore 中检索按另一个集合分组的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55622691/

相关文章:

Firebase Cloud Firestore 抛出 "client is offline"

javascript - 系列 promise

promise - Promise 对象内外的分号

javascript - 如何从 NestJS 的模块导入中获取配置?

javascript - Protractor 无限循环

javascript - 正则表达式验证器 - 如何包含某些特殊字符

带/不带 var 的 JavaScript 命名空间

android - 社交网络 - 使用 firebase 数据库关注功能

javascript - firebase promise 更改时范围变量不绑定(bind)

javascript - IBM Bluemix Node.js 原生 Promise 支持