私のアプリケーションにとって、Firebase のコレクションから複数のドキュメントをランダムに選択できることが重要です。
Firebase には、これを行うクエリを実装するための組み込みネイティブ関数 (私が知っている) がないため、最初に考えたのは、クエリ カーソルを使用してランダムな開始インデックスと終了インデックスを選択することでした。数値コレクション内のドキュメントの数。
このアプローチは機能しますが、各ドキュメントは毎回隣接するドキュメントとともに順番に提供されるため、限られた方法でのみ機能します。ただし、親コレクション内のインデックスによってドキュメントを選択できる場合は、実装することができます。ランダムなドキュメント クエリですが、問題は、これを行う方法、またはこれが可能であるかどうかを説明したドキュメントが見つからないことです。
これが私がやりたいことです。次の Firestore アーキテクチャを考えてみましょう:
リーリー次に、クライアント側 (私は Swift 環境にいます) で、これを行うクエリを書きたいと思います:
リーリー同様のことはできますか?あるいは、同様の方法でランダムなドキュメントを選択する他の方法はありますか?
###助けてください。P粉6681137682023-10-20 09:51:55
今後この問題に遭遇する人を助けるためにこれを投稿します。
自動 ID を使用する場合は、Dan McGrath の回答 <中所述< /a>.
のように、新しい自動 ID を生成し、最も近い自動 ID をクエリできます。私は最近、Firestore コレクションからランダムな引用符を取得する必要があるランダムな引用符 API を作成しました。
これが私がこの問題を解決した方法です:
クエリのキーは次のとおりです:
リーリードキュメントが見つからない場合は、逆の操作で再度呼び出します。
###お役に立てれば!P粉9856865572023-10-20 09:50:51
ランダムに生成されたインデックスと単純なクエリを使用して、Cloud Firestore のコレクションまたはコレクション グループからドキュメントをランダムに選択できます。
この回答は 4 つの部分に分かれており、各部分には異なるオプションがあります:
この回答の基礎は、昇順または降順で並べ替えたときにすべてのドキュメントがランダムに並べ替えられるインデックス フィールドを作成することです。これを作成するにはさまざまな方法があるので、最も簡単な方法から始めて 2 を見てみましょう。
当社のクライアント ライブラリで提供されるランダムに生成された自動 ID を使用する場合、同じシステムを使用してドキュメントをランダムに選択できます。この場合、ランダムに並べられたインデックス が ドキュメント ID になります。
後のクエリ セクションで、生成するランダムな値は、新しい自動 ID (iOS、Android、Web) です。クエリされるフィールドは次のとおりです。 __name__
フィールド、および後述の「下限値」は空の文字列です。これはランダムなインデックスを生成する最も簡単な方法であり、言語やプラットフォームに関係なく機能します。
デフォルトでは、ドキュメント名 (__name__
) は昇順でのみインデックス付けされ、既存のドキュメントの名前を変更するには、ドキュメントを削除して再作成する必要があります。これらのいずれかが必要な場合でも、この方法を使用できます。この目的でドキュメント名をオーバーロードする代わりに、自動 ID を random
という名前の実際のフィールドとして保存するだけです。
ドキュメントを作成するときは、まず制限された範囲内でランダムな整数を生成し、それを random
という名前のフィールドに設定します。予想されるドキュメントの数に応じて、異なる境界範囲を使用してスペースを節約したり、競合のリスクを軽減したりできます (これにより、この手法の有効性が低下します)。
考慮すべき点は異なるため、どの言語が必要か検討する必要があります。 Swift はシンプルですが、JavaScript には顕著な問題があります:
これにより、ランダムに並べ替えられたドキュメントのインデックスが作成されます。後のクエリ セクションで、生成するランダム値はこれらの値の別の値になり、後述する「下限値」は -1 になります。
ランダムなインデックスを作成したので、それをクエリする必要があります。以下では、ランダムな 1 つのドキュメントを選択するいくつかの簡単なバリエーションと、複数の 1 ドキュメントを選択するオプションを見ていきます。
これらすべてのオプションでは、ドキュメントの作成時に作成したインデックス値と同じ形式で新しいランダム値を生成する必要があります。これは、以下の変数 random
で表されます。この値を使用して、インデックス上のランダムなポイントを見つけます。
書類が返却されたかどうかを確認してください。そうでない場合は、ランダム インデックスの「低い値」を使用して再度クエリを実行します。たとえば、ランダムな整数を実行する場合、
lowValue は 0
: となります。
リーリー
ドキュメントが 1 つある限り、少なくとも 1 つのドキュメントが返されることが保証されます。
両方向
一方向にクエリを実行して値が見つからない場合に折り返すのではなく、
>= と <=
のどちらかをランダムに選択できるため、値が不当にマスクされる可能性が低くなります。インデックス ストレージを 2 倍にする代わりに、コストは半分になります。
<=
一方向で結果が返されない場合は、他の方向に切り替えます:
複数のランダムなドキュメントを選択します
洗い流して繰り返します
この方法では、同じパターンが繰り返し表示されることを心配することなく、ランダムなドキュメントのシーケンスが得られます。
トレードオフは、各ドキュメントを提供するために個別のラウンドトリップが必要なため、次の方法よりも時間がかかることです。
###それを維持する###この方法では、必要な書類の制限数を増やすだけです。呼び出し内で
0..limitこのソリューションのトレードオフは、シーケンスが繰り返されることです。ドキュメントはランダムに並べ替えられますが、範囲が重複する場合は、前に見たのと同じパターンが表示されます。この懸念を軽減する方法があります。それについては、再シードに関する次のセクションで説明します。
この方法は、最良の場合は 1 回の呼び出しで、最悪の場合は 2 回の呼び出しですべてのドキュメントを要求するため、「リンスして繰り返す」よりも高速です。
一貫したランダム性を実現するための再シード
ドキュメント セットが静的な場合、このメソッドはドキュメントをランダムに提供しますが、各ドキュメントが返される確率も静的になります。一部の値は、取得元の最初のランダム値に応じて、不当に低い確率または高い確率を持つ可能性があるため、これは問題です。多くのユースケースではこれで問題ありませんが、場合によっては、長期的なランダム性を高めて、任意の 1 つのドキュメントが返される可能性をより均等にする必要がある場合があります。
再シードについて心配する必要はありません。いつでもドキュメントごとに複数のランダムなインデックスを作成し、毎回そのうちの 1 つをランダムに選択できます。たとえば、フィールド random
をサブフィールド 1 ~ 3 を含むマップとします。
リーリー
書き込み時にシードをリセット
random フィールドのランダム値が再生成されます。これにより、ドキュメントがランダムなインデックスに移動されます。
書き込みはコストが高く、ホットスポットになる可能性があるため、読み取り時間のサブセットでのみ更新することを選択できます (例:
if random(0,100) === 0) update; )。