繁体   English   中英

Firestore - 如何确定地从集合中获取多个随机(非重复的、特定数量的)文档?

[英]Firestore - How to get multiple random (non duplicated, specific number of) documents from a collection with certainty?

使用https://stackoverflow.com/a/46801925/3073280 中的Dan McGrath 解决方案(生成和查询随机索引),只要集合有一个或多个文档,我当然可以肯定地获得一个随机文档。 换句话说,获取一个随机文档很容易。

但是,我很难实施 Dan McGrath 的解决方案来确定地从集合中获取多个随机(非重复)文档。 我指的是 Dan McGrath 的冲洗和重复解决方案。

那么,参考我下面的伪代码,当集合有 5 个文档时,如何随机获得 3 个文档*(非重复)?

import { Component, OnInit } from '@angular/core';

import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { throwError, interval, of }  from 'rxjs';
import { retry, switchMap, mergeMap, take } from 'rxjs/operators';


@Component({
  selector: 'app-firestore',
  templateUrl: './firestore.component.html',
  styleUrls: ['./firestore.component.css']
})
export class FirestoreComponent implements OnInit {

  constructor(private afs: AngularFirestore) {

  } 

  // This is the sample data structure in Firestore with only 5 documents in the collection
  // -Collection name is testRandom
  // --Document Auto ID
  // --- { random: 1 }
  // --Document Auto ID
  // --- { random: 2 }
  // --Document Auto ID
  // --- { random: 4, remark: 'intentionally skip 3' }
  // --Document Auto ID
  // --- { random: 5 }
  // --Document Auto ID
  // --- { random: 7, remark: 'intentionally skip 6' }

  getRandomIntInclusive(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1) + min); //The maximum is inclusive and the minimum is inclusive
  }

  /*
  * This will return one document at random but this will not guarantee return if the random number is 3 or 6
  * */
  selectSingleRandomDocument_byQueryingRandomIndexes() {
    return this.afs.collection<Item>('testRandom',
        ref => ref.where('random', '==', this.getRandomIntInclusive(1,7)).limit(1)
    )
      .valueChanges()
      .pipe(
        mergeMap(doc => {
          if (doc.length > 0) {
            return of(doc);
          } else {
            return throwError('no random document queried because the random number is either 3 or 6, hence throw error so it will retry')
          }
        }),
      )
  }

  /*
  * This will query for 3 documents but it will not guarantee return 3 documents if error thrown
  * */
  rinseAndRepeat() {
    interval(2000)
      .pipe(
        take(3),
        switchMap(val => this.selectSingleRandomDocument_byQueryingRandomIndexes()
            .pipe(retry(5)) // return 5 times if get throwError from singleRandomDocument
        )
      )
      .subscribe();
  }

}

简而言之,当集合有 5 个文档时,如何随机获得 3 个文档*(非重复)?

*注意:在生产中,它会从集合中的数千个文档中随机查询 80 个文档; 因此,请不要建议阅读整个集合并随机打乱文档,然后阅读前 80 个文档。

看起来就像在查询之前检查随机整数以确保它们是唯一的一样简单。 在反应中可能有更优雅的方法来实现这一点,但这似乎是可行的。

getSetOfRandomInts(num) {
   const set = new Set();
   while(set.size < num) { // retry if we get dups
     set.add(this.getRandomIntInclusive(1,7));
   }
   return set;
}

selectSingleDocumentByRandomIndex(randomNumber) {
    return this.afs.collection<Item>('testRandom',
        ref => ref.where('random', '==', randomNumber).limit(1)
    )
      .valueChanges()
      .pipe(
        mergeMap(doc => {
          if (doc.length > 0) {
            return of(doc);
          } else {
            return throwError('no random document queried because the random number is either 3 or 6, hence throw error so it will retry')
          }
        }),
      )
  }

rinseAndRepeat() {
    interval(2000)
      .pipe(
        () => this.getSetOfRandomInts(3),
        switchMap(randomInt => this.selectSingleDocumentByRandomIndex(randomInt)
            .pipe(retry(5))
        )
      )
      .subscribe();
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM