首页 > 解决方案 > Firestore 查询:在某个日期后按计数排序

问题描述

假设有大量这样的文档的集合:

{
  createdAt: 1630789008561, // timestamp
  count: 5
},
{
  createdAt: 1630788666511, // timestamp
  count: 50
},
...

我想查询在某个时间戳之后创建的具有最高计数的 50 个文档。

一个简单的解决方案是在此特定时间戳之后查询所有文档,然后自行排序。但我不能,因为我的数据库太大了。

我的第一次查询尝试是:

db.collection("docs")
  .where("createdAt", ">", timestamp)
  .orderBy("count", "desc")
  .limit(50)
  .get();

此查询在 Firestore 中不起作用并抛出:

错误:3 INVALID_ARGUMENT:不等式过滤器属性和第一排序顺序必须相同:createdAt 和 count`

然后我尝试了:

db.collection("docs")
  .where("createdAt", ">", timestamp)
  .orderBy("createdAt", "desc")
  .orderBy("count", "desc")
  .limit(50)
  .get()

这个查询对我不起作用,因为它的作用是在时间戳之后获取 50 个文档,然后按计数对它们进行排序,以防它们具有相同的时间戳,这不是我想要的。

编辑为什么这个查询不起作用:

如果我有 150 个文件:

如果我使用时间戳为 0 的查询,我将取回上次创建的 50 个文档(因为我正在使用.orderBy("createdAt", "desc")),这些文档的计数为 1,显然不是计数最高的文档。如果您asc改用,您将获得第一个文档,但仍然不是最高计数。我想要一个查询,时间戳为 0 会给我 50 个文档,计数为 2。

我怎样才能达到我想要的?

编辑我目前正在使用的解决方案(我想更改):

由于我的时间范围是一天,所以我day在每个文档中添加一个字段,如下所示:

{
  day: '2021-09-06',
  createdAt: 1630789008561, // timestamp
  count: 5
},
{
  day: '2021-09-05',
  createdAt: 1630788666511, // timestamp
  count: 50
},
...

然后我可以像这样进行平等检查:

db
  .collection("docs")
  .where("day", "==", '2021-09-05')
  .orderBy("count", "desc")
  .limit(50)
  .get();

这可行,但这并不是很好,因为每次我的时间范围发生变化时,我都需要更新我的数据库架构并使用新字段更新每个文档。

标签: javascriptfirebasegoogle-cloud-platformgoogle-cloud-firestore

解决方案


返回按计数排序的前 50 个文档。然后您按设备上的时间戳进行过滤。

QuerySnapshot<Map<String, dynamic>> query = await db
    .collection("docs")
    .orderBy("count", "desc")
    .limit(50)
    .get();
List docs = query.docs.map((e) => e.data()).toList();
// then filter by timestamp on the device
docs.removeWhere((element) => element['createdAt'] < timestamp);

这不能通过使用 where 查询来完成,因为没有办法绕过这个限制

如果您包含具有范围比较(<、<=、>、>=)的过滤器,则您的第一个排序必须在同一字段上:


推荐阅读