Firestore - 如何确定地从集合中获取多个随机(非重复的,特定数量的)文档?
Firestore - How to get multiple random (non duplicated, specific number of) documents from a collection with certainty?
使用 中 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 个文档。
看起来就像在查询之前检查随机整数以确保它们是唯一的一样简单。在 React 中可能有更优雅的方法来实现这一点,但这似乎可行。
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();
}
使用
但是,我很难实施 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 个文档。
看起来就像在查询之前检查随机整数以确保它们是唯一的一样简单。在 React 中可能有更优雅的方法来实现这一点,但这似乎可行。
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();
}