Firestore: How to get random documents in a collec

2019-01-03 06:47发布

It is crucial for my application to be able to select multiple documents at random from a collection in firebase.

Since there is no native function built in to Firebase (that I know of) to achieve a query that does just this, my first thought was to use query cursors to select a random start and end index provided that I have the number of documents in the collection.

This approach would work but only in a limited fashion since every document would be served up in sequence with its neighboring documents every time; however, if I was able to select a document by its index in its parent collection I could achieve a random document query but the problem is I can't find any documentation that describes how you can do this or even if you can do this.

Here's what I'd like to be able to do, consider the following firestore schema:

root/
  posts/
     docA
     docB
     docC
     docD

Then in my client (I'm in a Swift environment) I'd like to write a query that can do this:

db.collection("posts")[0, 1, 3] // would return: docA, docB, docD

Is there anyway I can do something along the lines of this? Or, is there a different way I can select random documents in a similar fashion?

Please help.

2条回答
Summer. ? 凉城
2楼-- · 2019-01-03 07:04

I have one way to get random a list document in Firebase Firestore, it really easy. When i upload data on Firestore i creat a field name "position" with random value from 1 to 1 milions. When i get data from Fire store i will set Order by field "Position" and update value for it, a lot of user load data and data always update and it's will be random value.

查看更多
冷血范
3楼-- · 2019-01-03 07:16

Document ID agnostic version

When you write a document, first generate a random 64-bit integer and add it as a field called random.

This will create an index with your documents randomly sorted.

Now, to select a random document, generate another random 64-bit integer. We'll use this in a query to pick a random position in the index and read the next document:

let postsRef = db.collection("posts")
queryRef = postsRef.whereField("random", isGreaterThan: random)
                   .order(by: "random")
                   .limit(to: 1)

Check that this has returned a document. If it doesn't, reverse the direction and try again:

queryRef = postsRef.whereField("random", isLessThanOrEqualTo: random)
                   .order(by: "random", descending: true)
                   .limit(to: 1)

Auto Id version

If you are using the randomly generated automatic ids provided in our client libraries, you can use this same system to randomly select a document.

In this system, generate a new auto id to use in the query. Now select documents (limit 1) in the collection that are greater than your new auto id.

One slight difference from the agnostic version is you can not currently order document ids in descending order. This means that if your query doesn't return a document, you'll need to generate a new auto id and try again.

Multiple random numbers

Often, you'll want to select more than 1 random document at a time. There are 2 different ways to adjust the above techniques depending on what trade offs you want.

Rinse & Repeat

This method is straight forward. Simply repeat the process, including selecting a new random integer each time.

This method will give you random sequences of documents without worrying about seeing the same patterns repeatedly.

The trade-off is it will be slower than the next method since it requires a separate round trip to the service for each document.

Keep it coming

In this approach, simply increase the number in the limit to the desired documents. It's a little more complex as you might return 0..limit documents in the call. You'll then need to get the missing documents in the same manner, but with the limit reduced to only the difference. If you know there are more documents in total than the number you are asking for, you can ignore the edge case of never getting back enough documents.

The trade off with this solution is in repeated sequences. While the documents are randomly ordered, if you ever end up overlapping ranges you'll see the same pattern you saw before. There are 2 ways to mitigate to this concern though. Firstly, inserted documents will end up weaved in-between, gradually changing the sequence. Secondly, you can accelerate this by updating the random field with a new number on each update.

This approach is faster than 'Rinse & Repeat' as you'll be requesting all the documents in a single call.

查看更多
登录 后发表回答