【问题标题】:Handling big amount of data in Firebase or how avoid "where 'in'" restrictions?在 Firebase 中处理大量数据或如何避免“在哪里”限制?
【发布时间】:2020-03-18 12:37:30
【问题描述】:

谁能帮我解决 Firestore 中的聚合查询。 似乎 Firestore 是关于限制和限制的。

我有两个集合,我需要使用.limit()过滤来抓取一定数量的用户,然后我需要在另一个集合中查找对应的记录。

我使用where in 过滤器进行的第二个查询,但显然我在where in 过滤器的查询数组中只能有10 个项目。

我设法处理此请求的唯一方法是:

           async ({ query }: Request, res: Response) => {
                const users: any = [];
                const ids: any = [];
                const stats: any = [];

                await firestore.collection('users').limit(30).get()
                    .then((snapshot) => {
                        let i = 1;
                        let d: any = [];

                        snapshot.forEach(doc => {
                            users.push(doc.data());

                            if (i <= 9) {
                                d.push(doc.data().id);
                                i++;
                            } else if (i === 10) {
                                d.push(doc.data().id);
                                i = 1;
                                ids.push(d);
                                d = [];
                            }

                        });

                    }).catch(console.log);

                const promises: any = [];

                ids.forEach((tens: any, index: number) => {
                    if (tens) {
                        promises.push(firestore.collection('users_statistic').
                            where('user_id', 'in', ids[index])
                            .get()
                            .then((snapshot) => {
                                const data: any = [];

                                snapshot.forEach(doc => data.push(doc.data()))
                                return data;
                            }))
                    }
                });

                await Promise.all(promises).then(stat => {
                    stat.forEach(t => {
                        stats.push(...(t as []));
                    })
                }).catch(console.log);

                const sortedStats: any = {};
                users.forEach((user: any) => {
                    sortedStats[user.id] = stats.filter((data: any) => data.user_id === user.id);
                });

                const totals = [];

                for (const key in sortedStats) {
                    if (sortedStats.hasOwnProperty(key)) {
                        const value = sortedStats[key];

                        const clicks = value.reduce((acc: any, v: any) => acc + v.clicks, 0);
                        const views = value.reduce((acc: any, v: any) => acc + v.page_views, 0);

                        totals.push({
                            ...users[key],
                            clicks,
                            views
                        })
                    }
                }

                res.status(200).send(totals);

}

  1. 我拿用户列表
  2. 获取他们的 id 并制作包含最多 10 个 id 的批量数组
  3. 制作请求列表并分配一个包含 10 个 ID 的数组(显然这不是一个好主意,我想避免它。我必须向 Firestore DB 发出许多请求)
  4. Promise.all 我履行所有承诺
  5. 过滤和排序结果准备输出数据

如果有任何帮助,我将不胜感激

提前致谢!

【问题讨论】:

  • 这是您第三次尝试提出同样的问题,虽然我可以看到您试图集中问题,但我仍然不明白您在问什么。如果我发布类似“是的,Firestore 上的聚合查询很难”之类的答案,那会是您正在寻找的答案吗?还是您发布的代码有问题?如果是这样,哪条线没有做你想做的事?如果您在帖子中写一个具体且重点突出的问题,这真的很有帮助。
  • Firestore 是关于速度和可扩展性的。为了实现这些,需要限制。为了充分利用 Firestore,我建议学习如何欣赏其优势并解决其局限性。 medium.com/firebase-developers/…
  • @FrankvanPuffelen 感谢您的回答!是的,这是我第二次尝试找出如何克服 Firestore 中的聚合限制。对于这个简单的任务,我必须建立 4 个数据库连接,但只有 2 个。是的,我完全同意可能存在一些限制,但我编写的代码在我看来太错误了。这就是为什么我阅读了大量的官方文档和文章,但无论如何只有限制.. 上面的代码是我试图从 Firebase 获取数据的方式 - 发出许多数据库请求,在准备查询时为不可预测的错误添加了一个位置?
  • @FrankvanPuffelen 这就是我感兴趣的……在我看来,我的代码使用起来很糟糕。我以为我做错了什么。所以我想听听有经验的人如何应对 Firestore 中的聚合。
  • 好的或坏的做法是一种意见,Stack Overflow 不适合。但客观地说,Firestore 可能不是运行临时聚合的最佳数据库。如果您需要进行临时聚合,您可能最好使用更适合此的数据库,例如 BigQuery,它擅长对任意大型数据集进行临时聚合查询。如果您想坚持使用 Firestore,请考虑预先聚合数据,这意味着您将聚合存储到数据库本身,并在每次相关的写入操作时更新它们。

标签: node.js firebase google-cloud-firestore google-cloud-functions


【解决方案1】:

如果您需要运行大量临时聚合,那么 Firestore 可能不是最适合您的数据库。在这种情况下,您可能最好使用更适合临时查询的数据库,例如 BigQuery,它擅长对任意大型数据集进行此类聚合查询。

如果您想坚持使用 Firestore,请考虑预先聚合数据,这意味着您将聚合存储到数据库本身,并在每次相关的写入操作时更新它们。这意味着您将无法再临时执行它们,并且您的写入操作变得更加复杂,但好在检索聚合信息将变得非常简单。

这是您将在 NoSQL 数据库中看到的常见权衡:您需要针对您的用例定制数据结构,并且通常会权衡读/写可扩展性和成本。

这个话题已经出现了好几次,所以也可以看看:

【讨论】:

  • 非常感谢弗兰克的回答!我还有一个问题。这是否可以在不使查询“全部读取”的情况下获得集合的大小?我的意思是我对查询使用“限制”过滤器,因为我不需要集合中的所有数据。但是当您在那里使用“限制”过滤器时,您只能看到当前请求的大小。我需要这些信息进行分页,这样我就可以知道期望的页面数量。在这里,我只能看到一种方法 - 抓住所有用户(超过 5k - 这不是很好,因为它对数据库读取很重要,而且成本太高),然后过滤数据
  • 获取集合中文档数的计数是最常见的聚合查询。它没有内置支持,您在此处的选项与我提到的所有其他聚合查询相同。文档中有一个示例,说明如何在文档中存储计数器并使其保持最新:firebase.google.com/docs/firestore/solutions/counters
  • 是的,我认为有一种内置方法可以获取记录数。所以,除了玩弄它所拥有的东西之外,我什么都没有了
猜你喜欢
  • 2012-11-23
  • 1970-01-01
  • 2016-12-28
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
  • 2016-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多