Firestore: How to Get Random Documents in a Collection

It is imperative that my application is able to select multiple random events from a collection in firebase.

Since there is no built-in function in Firebase (what I know) to achieve a query that does just that, 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 collection.

This approach will work, but only in a limited way, since each document will be serviced sequentially with its neighboring documents each time; however, if I could select a document by its index in my parent collection, I could get a random request for the document, but the problem is that I cannot find the documentation describing how you can do this, or even if you can to do.

Here, what I would like to do is consider the following firestore scheme:

root/
  posts/
     docA
     docB
     docC
     docD

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

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

Anyway, can I do something in accordance with this? Or is there another way to select random documents in a similar way?

Please, help.

+28
source share
5

, Cloud Firestore.

4 :

, . , 2, .

, , . .

, , - - (iOS, Android, Web), , , - __name__, " " - . , .

(__name__) , . - , random, .

, random. , ( ).

, , . Swift , JavaScript, , :

  • 32- : (~ 10K )
  • 64- : (: JavaScript , )

, . , , , " " -1.

, , . 1 , 1.

, , , random . , .

, , :

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

, . , , " " . , , lowValue 0:

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

, 1 .

. . , 3 (A, B, C) 10K A: 409496, B: 436496, C: 818992, A C 1/10K, B A 1/160K .

, , , >= <=, .

, :

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

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

1 . 2 , .

&

. , .

, , .

, , , .

. , 0..limit . , , . , , , , , ( ).

. , - , , . , .

, " & , - - 2 .

, , , , . , , , . , , 1 .

, , , . / , , .

Multi-Random

, , , . , random 1 3:

{'random': {'1': 32456, '2':3904515723, '3': 766958445}}

, , , 1, . , , ( ) .

, , random. .

( , ), . , , .

, (, if random(0,100) === 0) update;).

+55

, , .

, , .

API , .
:

var db = admin.firestore();
var quotes = db.collection("quotes");

var key = quotes.doc().id;

quotes.where(admin.firestore.FieldPath.documentId(), '>=', key).limit(1).get()
.then(snapshot => {
    if(snapshot.size > 0) {
        snapshot.forEach(doc => {
            console.log(doc.id, '=>', doc.data());
        });
    }
    else {
        var quote = quotes.where(admin.firestore.FieldPath.documentId(), '<', key).limit(1).get()
        .then(snapshot => {
            snapshot.forEach(doc => {
                console.log(doc.id, '=>', doc.data());
            });
        })
        .catch(err => {
            console.log('Error getting documents', err);
        });
    }
})
.catch(err => {
    console.log('Error getting documents', err);
});

:

.where(admin.firestore.FieldPath.documentId(), '>', key)

, .

, !
, API GitHub

+9

Angular 7 + RxJS, , .

@Dan McGrath : + . , : RxJS, If-Else? if/else ( - ).

, angularfire2 Firebase Angular.

:

import { Component, OnInit } from '@angular/core';
import { Observable, merge, pipe } from 'rxjs';
import { map, switchMap, filter, take } from 'rxjs/operators';
import { AngularFirestore, QuerySnapshot } from '@angular/fire/firestore';

@Component({
  selector: 'pp-random',
  templateUrl: './random.component.html',
  styleUrls: ['./random.component.scss']
})
export class RandomComponent implements OnInit {

  constructor(
    public afs: AngularFirestore,
  ) { }

  ngOnInit() {
  }

  public buttonClicked(): void {
    this.getRandom().pipe(take(1)).subscribe();
  }

  public getRandom(): Observable<any[]> {
    const randomNumber = this.getRandomNumber();
    const request$ = this.afs.collection('your-collection', ref => ref.where('random', '>=', randomNumber).orderBy('random').limit(1)).get();
    const retryRequest$ = this.afs.collection('your-collection', ref => ref.where('random', '<=', randomNumber).orderBy('random', 'desc').limit(1)).get();

    const docMap = pipe(
      map((docs: QuerySnapshot<any>) => {
        return docs.docs.map(e => {
          return {
            id: e.id,
            ...e.data()
          } as any;
        });
      })
    );

    const random$ = request$.pipe(docMap).pipe(filter(x => x !== undefined && x[0] !== undefined));

    const retry$ = request$.pipe(docMap).pipe(
      filter(x => x === undefined || x[0] === undefined),
      switchMap(() => retryRequest$),
      docMap
    );

    return merge(random$, retry$);
  }

  public getRandomNumber(): number {
    const min = Math.ceil(Number.MIN_VALUE);
    const max = Math.ceil(Number.MAX_VALUE);
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }
}

+2

Firebase Firestore, . Firestore, "position" 1 1 . Fire store, "" , , .

0

, Angular + Firestore, @Dan McGrath, .

1 .

  getDocumentRandomlyParent(): Observable<any> {
    return this.getDocumentRandomlyChild()
      .pipe(
        expand((document: any) => document === null ? this.getDocumentRandomlyChild() : EMPTY),
      );
  }

  getDocumentRandomlyChild(): Observable<any> {
      const random = this.afs.createId();
      return this.afs
        .collection('my_collection', ref =>
          ref
            .where('random_identifier', '>', random)
            .limit(1))
        .valueChanges()
        .pipe(
          map((documentArray: any[]) => {
            if (documentArray && documentArray.length) {
              return documentArray[0];
            } else {
              return null;
            }
          }),
        );
  }

1).expand() rxjs , , .

2) For recursion to work properly, we need to have 2 separate functions.

3) We use EMPTY to complete the .expand () statement.

import { Observable, EMPTY } from 'rxjs';
0
source

Source: https://habr.com/ru/post/1687679/


All Articles