Firestore:文档中的引用数组到具有对象数组的对象(AngularFire)
Firestore: Array of references within a document into an object with array of objects (AngularFire)
我有一个集合,其中每个文档都有一个引用数组。
Firestore中的结构是这样的:
collection1
doc1
doc2
doc3
name: string
...
refs: Array
collection2/x786123nd...
collection2/z1237683s...
...
我想将其转换为:
[
{<doc1 as object>},
{<doc2 as object},
{ name: "Document 3", refsResult:
[
{<object here mapped from reference>},
{<object here mapped from reference>},
]
}
]
长话短说,我需要从 firebase 获取对象列表的输出,其中每个对象都有一个对象列表而不是引用。
以下代码段不工作
我正在尝试在 Angular 的服务级别使用 RxJS 来转换输出,如下所示:
return this.afs.collection('collection1')
.valueChanges()
.pipe(
switchMap(objects => from(objects).pipe(
switchMap(obj => from(obj.refs).pipe(
switchMap(ref => ref.get()),
map(r => ({ ...obj, refsResult: r.data() })),
tap(obj => console.log('OBJ', obj)),
)),
)),
tap(objects => console.log(objects))
);
但似乎我只收到一个对象,而不是包含 2 个对象的列表。此外,refsResult 似乎也是单个对象,而不是数组。我确定我使用的 switchMaps 有误,可能他们正在取消其他结果或类似结果。
我想将解决方案保留在 rxjs 运算符链中。
编辑 1
我以一种 hacky 的方式让它工作,我只是在这里分享它以提供更多上下文,看看我们是否可以找到一种方法来使用 RxJS。
return this.afs.collection('collection1')
.valueChanges()
.pipe(
tap(objects => {
objects.forEach(object => {
object.refsResult = [];
object.refs.forEach(ref => {
ref.get().then(d => object.refsResult.push(d.data()));
})
})
}),
tap(programs => console.log(programs))
);
上面的代码工作但不是很好,因为首先 return 集合,然后改变对象以将项目注入数组中。希望对您有所帮助。
非常感谢您的帮助! :)
您可以使用 combineLatest
创建一个发射数据数组的单个可观察对象。
在你的例子中,我们可以嵌套使用它两次:
- 处理集合中的每个对象
- 为每个对象处理 refs 数组中的每个 ref
结果是一个单独的可观察对象,它发出完整的对象集合,每个对象都有其完整的引用结果数据集合。然后你只需要一个
switchMap
处理订阅这个单一的 observable:
return this.afs.collection('collection1').valueChanges().pipe(
switchMap(objects => combineLatest(
objects.map(obj => combineLatest(
obj.refs.map(ref => from(ref.get()).pipe(map(r => r.data())))
).pipe(
map(refsResult => ({ ...obj, refsResult }))
)
))
))
);
为了便于阅读,我可能会创建一个单独的函数:
function appendRefData(obj) {
return combineLatest(
obj.refs.map(ref => ref.get().pipe(map(r => r.data())))
).pipe(
map(refsResult => ({ ...obj, refsResult }))
);
}
return this.afs.collection('collection1').valueChanges().pipe(
switchMap(objects => combineLatest(objects.map(appendRefData)))
);
我有一个集合,其中每个文档都有一个引用数组。
Firestore中的结构是这样的:
collection1
doc1
doc2
doc3
name: string
...
refs: Array
collection2/x786123nd...
collection2/z1237683s...
...
我想将其转换为:
[
{<doc1 as object>},
{<doc2 as object},
{ name: "Document 3", refsResult:
[
{<object here mapped from reference>},
{<object here mapped from reference>},
]
}
]
长话短说,我需要从 firebase 获取对象列表的输出,其中每个对象都有一个对象列表而不是引用。
以下代码段不工作
我正在尝试在 Angular 的服务级别使用 RxJS 来转换输出,如下所示:
return this.afs.collection('collection1')
.valueChanges()
.pipe(
switchMap(objects => from(objects).pipe(
switchMap(obj => from(obj.refs).pipe(
switchMap(ref => ref.get()),
map(r => ({ ...obj, refsResult: r.data() })),
tap(obj => console.log('OBJ', obj)),
)),
)),
tap(objects => console.log(objects))
);
但似乎我只收到一个对象,而不是包含 2 个对象的列表。此外,refsResult 似乎也是单个对象,而不是数组。我确定我使用的 switchMaps 有误,可能他们正在取消其他结果或类似结果。
我想将解决方案保留在 rxjs 运算符链中。
编辑 1 我以一种 hacky 的方式让它工作,我只是在这里分享它以提供更多上下文,看看我们是否可以找到一种方法来使用 RxJS。
return this.afs.collection('collection1')
.valueChanges()
.pipe(
tap(objects => {
objects.forEach(object => {
object.refsResult = [];
object.refs.forEach(ref => {
ref.get().then(d => object.refsResult.push(d.data()));
})
})
}),
tap(programs => console.log(programs))
);
上面的代码工作但不是很好,因为首先 return 集合,然后改变对象以将项目注入数组中。希望对您有所帮助。
非常感谢您的帮助! :)
您可以使用 combineLatest
创建一个发射数据数组的单个可观察对象。
在你的例子中,我们可以嵌套使用它两次:
- 处理集合中的每个对象
- 为每个对象处理 refs 数组中的每个 ref
结果是一个单独的可观察对象,它发出完整的对象集合,每个对象都有其完整的引用结果数据集合。然后你只需要一个
switchMap
处理订阅这个单一的 observable:
return this.afs.collection('collection1').valueChanges().pipe(
switchMap(objects => combineLatest(
objects.map(obj => combineLatest(
obj.refs.map(ref => from(ref.get()).pipe(map(r => r.data())))
).pipe(
map(refsResult => ({ ...obj, refsResult }))
)
))
))
);
为了便于阅读,我可能会创建一个单独的函数:
function appendRefData(obj) {
return combineLatest(
obj.refs.map(ref => ref.get().pipe(map(r => r.data())))
).pipe(
map(refsResult => ({ ...obj, refsResult }))
);
}
return this.afs.collection('collection1').valueChanges().pipe(
switchMap(objects => combineLatest(objects.map(appendRefData)))
);