【问题标题】:Firebase date range query to fetch documents that have starDate and endDateFirebase 日期范围查询以获取具有 starDate 和 endDate 的文档
【发布时间】:2019-04-29 15:37:06
【问题描述】:

我的 Firestore 数据库中有一组这样的任务:

"tasks": {
    v8NC4GovVOPe21fhwtp0 : {
        id: "v8NC4GovVOPe21fhwtp0"
        status: 0
        dateFrom: 30 april 2019 at 00:00:00 UTC-3
        dateTo: 05 may 2019 at 00:00:00 UTC-3
        ....
    },
    v7NC4GaxVOPe48ftstp1 : {
        id:"v7NC4GaxVOPe48ftstp1"
        status: 0
        dateFrom: 29 april 2019 at 00:00:00 UTC-3
        dateTo: 02 may 2019 at 00:00:00 UTC-3
        ....
    }
}

文档有一个dateFrom 字段,表示用户可以开始处理该任务的第一个日期,还有一个dateTo 字段,表示用户必须完成该任务的最后一天。

我试图从 2019 年 4 月开始获取所有任务,这意味着 dateFromdateTo 属于本月/年的那些(在本例中,如果月份是 2019 年 4 月,它必须同时获取任务)。

在 Android 上,我得到所选月份的第一个日期 (startDate) 和所选月份的最后一个日期 (endDate),我正在尝试执行以下操作:

val missionsCollection = FirebaseFirestore.getInstance()
        .collection("/users").document(uid).collection("tasks")
        .whereGreaterThanOrEqualTo("dateFrom", startDate).whereLessThanOrEqualTo("dateTo", endDate)

但我收到一条错误消息,提示 All where filters other than whereEqualTo() must be on the same field. But you have filters on 'dateFrom' and 'dateTo'

我想过一些解决方法,但它们看起来都很糟糕,即使我找不到一个好的解决方案,我相信一定有一个。

【问题讨论】:

    标签: android firebase kotlin nosql google-cloud-firestore


    【解决方案1】:

    Firestore 允许链接多个“where()”方法来创建更具体的查询,但仅限于同一字段。正如您在Query limitations 的官方文档中可能看到的那样:

    Cloud Firestore 不支持以下类型的查询:

    • 在不同字段上使用范围过滤器进行查询,如上一节所述。

    因此禁止对不同字段进行范围过滤。

    为了达到你想要的,你需要查询你的数据库两次,一次是使用调用来过滤数据:

    .whereGreaterThanOrEqualTo("dateFrom", startDate)
    

    第二次使用调用:

    .whereLessThanOrEqualTo("dateTo", endDate)
    

    但很遗憾,您不能在同一个查询中使用它们。

    编辑:

    当我们设计数据库架构时,基本上我们会为查询构建它。因此,除了上述解决方案(您可以过滤查询中的一个字段以及客户端代码中的另一个字段)之外,还有另一种方法可以将两个范围的值组合到一个字段中某种方式可以让您的用例使用单个字段。

    到目前为止,我见过的最成功的例子之一是 Geohashes 中用于过滤纬度和经度的组合,正如 Frank van Puffelen 在以下视频中所解释的那样:

    知道这两种解决方案在工作量上的区别,我建议使用第一种。

    还有第三种解决方案,您应该将 3 月至 4 月的所有任务添加到一个集合中。然后您可以使用以下命令查询这个新集合:

     db.collection("tasks-aps-mar")
        .whereGreaterThanOrEqualTo("day", 1)
        .whereLessThanOrEqualTo("day", 30);
    

    更通用的解决方案是将每个月的任务存储在一个集合中,然后执行查询以获取与所需月份对应的所有任务。在您的用例中,您应该查询数据库以获取 tasks-mar-2019tasks-apr-2019tasks-may-2019 等每个集合之一中的文档。

    关于您的评论,使用数组对您毫无帮助,因为您不能使用范围间隔。

    【讨论】:

    • “查询两次”是指对 firebase 进行两次不同的调用,然后创建一个列表,其中包含在两次调用中获取的任务?
    • 我知道这是对 firebase 的限制,我非常感谢您的帮助 :) 但是,我不确定获取比我的整个集合更多的文档的解决方案是否可行(考虑定价和阅读时间)
    • 我想有一个“月-年”数组,这样我就可以做这样的事情:.whereArrayContains("months", "04-2019")。你觉得这个选项怎么样?
    • 目前这是文档所述。另请参阅我从替代解决方案中更新的答案。
    • 感谢您的帮助,很抱歉我花了一些时间才接受您的回答。事实证明,我项目的 PO 决定只有一个日期字段,但无论如何,这些都是我们在 firebase 土地上的解决方案。
    猜你喜欢
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    相关资源
    最近更新 更多