如何使用 angularfire2 valuechanges 方法获取随机数据
Posted
技术标签:
【中文标题】如何使用 angularfire2 valuechanges 方法获取随机数据【英文标题】:How to get random data with angularfire2 valuechanges method 【发布时间】:2018-06-29 01:50:40 【问题描述】:我有questions$
observable,它从Firestore
返回超过10
问题对象。
this.questions$ = this.moduleCollection$.doc(module.id)
.collection('questions').valueChanges();
现在我想用10
随机问题限制结果。
我可以像这样限制查询
this.questions$ = this.moduleCollection$.doc(module.id)
.collection('questions',ref => ref.limit(10)).valueChanges();
但是不知道怎么随机获取,有Rxjs
运营商这样做吗?
我尝试过的(扩展@Richard Matsen 的回答)
const sampleSize = 2
const randomIndex = (array) => Math.floor(Math.random() * array.length)
const addIndexes = (array) => array.map((item, index) =>
item['id'] = index
return item
)
const removeIndexes = (array) => array.map(item =>
delete item.id
return item
)
this.questions$ =
this.moduleCollection$.doc(module.id).collection('questions').valueChanges()
.map(addIndexes)
.map(r => r[randomIndex(r)])
.repeat()
.scan((a, c) => a.map(a => a.id).indexOf(c.id) === -1 ? a.concat(c) : a, [])
.skipWhile(array => array.length < sampleSize)
.take(1)
.map(array => array.sort((a, b) => a.id - b.id))
.map(removeIndexes)
【问题讨论】:
查看this answer。它是用 Java 编写的,但用 javascript 转换它应该不难 【参考方案1】:此示例演示了一种纯 rxjs 方法,用于从数组中随机抽取样本,没有重复。
const source = Rx.Observable.of([val: 'a', val: 'b', val: 'c', val: 'd', val: 'e'])
const sampleSize = 2
const randomIndex = (array) => Math.floor(Math.random() * array.length)
const addIndexes = (array) => array.map((item, index) =>
item['id'] = index
return item
)
const removeIndexes = (array) => array.map(item =>
delete item.id
return item
)
const randomSample = (source, sampleSize) =>
source
.map(addIndexes)
.map(r => r[randomIndex(r)])
.repeat()
.scan((a, c) => a.map(a => a.id).indexOf(c.id) === -1 ? a.concat(c) : a, [])
.skipWhile(array => array.length < sampleSize)
.take(1)
.map(array => array.sort((a, b) => a.id - b.id))
.map(removeIndexes)
randomSample(source, sampleSize).subscribe(console.log)
.as-console-wrapper max-height: 100% !important; top: 0;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
使用 firestore .valueChanges()
firestore .valueChanges()
方法旨在每次云上的数据发生变化时推送新数组,因此这个可观察源永远不会完成。
这意味着 repeat()
永远不会触发。为了让它工作,我们需要封装采样代码。
const source = Rx.Observable.of([val: 'a', val: 'b', val: 'c', val: 'd', val: 'e'])
const sampleSize = 2
const randomIndex = (array) => Math.floor(Math.random() * array.length)
const addIndexes = (array) => array.map((item, index) =>
item['id'] = index
return item
)
const removeIndexes = (array) => array.map(item =>
delete item.id
return item
)
const randomSample = (source, sampleSize) =>
source
.mergeMap(array =>
Rx.Observable.of(array)
.map(addIndexes)
.map(r => r[randomIndex(r)])
.repeat()
.scan((a, c) => a.map(a => a.id).indexOf(c.id) === -1 ? a.concat(c) : a, [])
.skipWhile(array => array.length < sampleSize)
.take(1)
.map(array => array.sort((a, b) => a.id - b.id))
.map(removeIndexes)
)
randomSample(source, sampleSize).subscribe(console.log)
.as-console-wrapper max-height: 100% !important; top: 0;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
使用非 Rx 采样
在上面的代码中突出的一点是,我们将数组的可观察对象转换为数组,然后再转换回数组的内部可观察对象(所有这些都是为了获得一个“完成”事件)。
所以,直接在数组上工作更实用。
(也已使用 firestore .valueChanges()
进行了测试)
const source = Rx.Observable.of([val: 'a', val: 'b', val: 'c', val: 'd', val: 'e'])
const sampleSize = 2
const getRandomUniqueSample = (arr, sampleSize) =>
let result = [],
taken = ;
while (result.length < Math.min(sampleSize, arr.length))
let x = Math.floor(Math.random() * arr.length);
if (!(x in taken))
result.push(arr[x])
taken[x] = null;
return result;
const randomSample = (source, sampleSize) =>
source
.mergeMap(array =>
Rx.Observable.of(getRandomUniqueSample(array, sampleSize))
)
randomSample(source, sampleSize).subscribe(console.log)
.as-console-wrapper max-height: 100% !important; top: 0;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
【讨论】:
感谢您的回答,我试过了,但有一些错误。我更新了我对我的问题感到厌倦的内容。请帮忙 啊,是的,你有一个对象数组,所以扫描必须更复杂一些。对象上是否有 id 属性,例如questionId
?
现在不行,但我可以通过.snapshotChanges
轻松完成。假设我有一个字段questionId
,类似于lpybtKeZpr7lPDZMQtcO
这可行,但这只是一个小的本地更改 - 确实不应该影响您访问 Firestore 的方式。无论如何,数组项都有一个索引,我会使用它,如果你觉得它更合适,你可以拨回它。
我有点担心 concat 错误,这可能是由于缺少导入。以上是关于如何使用 angularfire2 valuechanges 方法获取随机数据的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 AngularFire2 和 Firebase 存储上传文件数组?
如何使用 angularfire2 valuechanges 方法获取随机数据
如何解决 rxjs Typescript 错误(Ionic 3,angularfire2)