-1

I need to make a Firestore query in a collection that:

  1. is ordered by field "timestamp"
  2. the field "uid" is equal to any of the elements of a strings array (more than 10)
  3. I need to paginate the query so that I'm able to perform later more queries starting from a precise timestamp

The code should look like this:

Firestore.firestore()
    .where(field: "uid", in: arrayOfUids)
    .order(by: "timestamp", descending: false)
    .limit(to: 5)

or in case of starting from a particular timestamp

Firestore.firestore()
    .where(field: "uid", in: arrayOfUids)
    .startAt("timestmap", lastTimestampFetched)
    .order(by: "timestamp", descending: false)
    .limit(to: 5)

How can I achieve this result? In this topic was suggested to perform multiple calls filtering with up to 10 elements in the array in each call (the maximum number of array elements for Firestore to be able to compare) but I didn't have the constraint of ordering by timestamp.

EDIT: I cannot order the query result client-side, it wouldn't be helpful for my use case. Let's say that we have 30 uids to query for: First, we have to divide these uids into groups of 10.

So we'll have 3 groups of 10 uids each (the max array lenght to for querying with Firestore); for each of this groups we'll do a separate query which looks like this:

Firestore.firestore()
        .where(field: "uid", in: arrayOfTenUids)
        .startAt("timestmap", lastTimestampFetched)
        .order(by: "timestamp", descending: false)
        .limit(to: 5)

For each query, we save the last document timestamp in order to be able to perform successive queries with pagination.

Here is the problem, we are going to have multiple last timestamps, since we are performing multiple queries, which timestamp are we going to save?

1st option: the last timestamp of all last timestamps

2nd option: the first timestamp of all last timestamps

1st case -> in successive queries we are going to fetch some documents that have been previously fetched

2nd case -> in successive queries we are going to miss some documents that have been previously fetched (because the last timestamp of one query could be after the last timestamp of another one)

This topic is really hard to explain but I did my best.

15
  • The question and the expected result is a bit unclear. The code in the question will return all documents that have a uid field value that matches one of the arrayOfUid's. Is that code not working? Or do you want to query for more than 10 values in the array? Commented Oct 22, 2021 at 16:55
  • exactly the second option, I want to query for more than 10 values in the array Commented Oct 22, 2021 at 16:57
  • The answer by @alexmamo in the link you provided is spot on. The ordering of said data will have no impact. Actually, thinking through that, you'll need to perform multiple queries and combine them in code anyway so that's the time to apply a sort - once you have all of the data. Is there something more? Commented Oct 23, 2021 at 15:00
  • I wanted to sort the documents using timestamp because, since the documents in the collection are a lot, I needed to paginate the query, and that's the reason why I wanted to order the data so that I can get some of them and not all the collection, but still have it ordered. Commented Oct 23, 2021 at 20:16
  • The answer in the topic suggested to combine the result of the queries in the client. Have you tried to sort it there? Commented Oct 25, 2021 at 15:05

1 Answer 1

2

Based on the comments let me try to create the current Firestore structure and re-state the objective, then suggest a solution. I am ignoring the timestamp for the moment:

Posts (collection)
   post_0
      uid: uid_4
   post_1:
      uid: uid_1
   post_2:
      uid: uid_3
   post_3:
      uid: uid_2

and then

Matches (collection)
   uid_0
      uid_1
      uid_2
      uid_3
   uid_5
      uid_4

The objective is for the current user, say uid_0, to read their node within the Matches collection which would be this

   uid_0
      uid_1
      uid_2
      uid_3

and then get the posts from the Post nodes where the uid field matches the uid's in that list. The result should be post_1, post_2 and post_3.

The issue is the users node, uid_0, could have dozens of child uid's and since Firestore can only match up to 10 at a time using the 'in' function

.where(field: "uid", in: arrayOfUids)

it would take multiple reads - and then there's the issue of the timestamp and sorting along with paginating.

My suggestion is to simplify; if the above stated goal is correct, instead of storing those different uid's with each post, just store the uid of the current user, like this

Posts (collection)
   post_0
      uid: uid_2
   post_1:
      uid: uid_0
   post_2:
      uid: uid_0
   post_3:
      uid: uid_0

Then query the Posts node for uid = uid_0. The result will be exactly the same and much simplier to implement and maintain and then the timestamp/pagination issue is no longer and issue.

Obviously this is a simple example; I would imagine you want to store multiple uid's within each post, so whichever user is logged in can retrieve their selection of posts. Do to that, use array contains to retrieve the posts that match for this user.

Posts (collection)
   post_0
      uid_array: 
         uid_2
         uid_9
         uid_21
Sign up to request clarification or add additional context in comments.

2 Comments

You completely understood what I meant, thanks so much for the answer. Basically, whenever a new match is created I need to add a new uid in "uid_array" to each Post corresponding to the matched uids . Obviously, I will do it serverside, do you think it's the right approach?
@StackGU Sounds like you're on track.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.