Firebase date range query to fetch documents that have starDate and endDate

天涯浪子 提交于 2020-06-23 04:53:27

问题


I have a collection of tasks on my Firestore database like this:

"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
        ....
    }
}

The document has a dateFrom field, which indicates the first date the user can start working on that task and an dateTo field, which indicates the last day the user have to finish that task.

I was trying to get all tasks from April 2019, which means the ones that either dateFrom or dateTo belongs to this month/year (in this example, if the month is April-2019, it must fetch both tasks).

On Android, I get the first date of the chosen month (startDate) and te last date from the chosen month (endDate) and I was trying to do something like:

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

But I get an error saying that All where filters other than whereEqualTo() must be on the same field. But you have filters on 'dateFrom' and 'dateTo'.

I thought about some workarounds, but they all look bad and even though I could not find a nice solution, I'm sure there's gotta be one.


回答1:


Firestore allows to chain multiple "where()" methods to create more specific queries but only on the same field. As you can probably see in the official documentation regardin Query limitations:

Cloud Firestore does not support the following types of queries:

  • Queries with range filters on different fields, as described in the previous section.

So range filters on different fields are forbidden.

To achieve what you want, you need to query your database twice, once to fiter data using a call to:

.whereGreaterThanOrEqualTo("dateFrom", startDate)

And second using a call to:

.whereLessThanOrEqualTo("dateTo", endDate)

But unfortunately you cannot use them in the same query.

Edit:

When we are designing a database schema, basically we structure it for our queries. So beside the above solution in which you can filter on one field in the query, and on the other field in your client-side code, there is also another approach in which you can combine the values of the two range into a single field in some way that will allow your use-case with a single field.

One of the most successful examples I've seen so far is the combination used in Geohashes to filter on latitude and longitude as explained by Frank van Puffelen in the following video:

  • https://www.youtube.com/watch?v=mx1mMdHBi5Q

Knowing the difference in effort between these two solutions, I'd recommend using the first one.

There is also a third solution, in which you should to add all tasks from Mar-Apr into a single collection. Then you could query this new collection with:

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

Even a more general solution would be to store the tasks in a collection for each month, and then perform a query to get all the tasks that correspond with the desired month. In your use case, you should query your database to get the documents within one of each collection tasks-mar-2019, tasks-apr-2019, tasks-may-2019 and so on.

Regarding your comment, using arrays won't help you at all since you cannot use range intervals.



来源:https://stackoverflow.com/questions/55906586/firebase-date-range-query-to-fetch-documents-that-have-stardate-and-enddate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!