Angular Observable:从数组映射单个值的问题
你的代码会每次输出所有ID的原因是:
usersDocRef.snapshotChanges()
会在
用户文档内容发生任何更新时触发一次
,每次触发你都把整个
projects
数组通过
from()
转换成了Observable流,这个流会依次发射数组里的每个元素。所以每次文档更新,都会完整遍历一遍数组,输出所有ID,而非单个新增/变化的ID。
分场景解决方案 #
场景1:仅首次加载时逐个输出ID
如果只需要在初始化时获取一次ID并逐个输出,给
snapshotChanges()
添加
take(1)
操作符,限制只取第一次文档快照:
const usersDocRef: AngularFirestoreDocument<any> = this.userCollectionRef.doc(this.userId); usersDocRef.snapshotChanges().pipe( take(1), // 仅获取一次文档快照 switchMap((ref) => { const usersProjectIds = ref.payload.data().projects; return from(usersProjectIds); ).subscribe((id) => { console.log(id);
场景2:仅输出数组的增量变化(新增/删除的ID)
如果需要监听数组的实际变化,只输出新增或删除的ID,需要对比前后两次快照的数组内容:
const usersDocRef: AngularFirestoreDocument<any> = this.userCollectionRef.doc(this.userId);
usersDocRef.snapshotChanges().pipe(
pairwise(), // 保留前一次快照用于对比
map(([prevSnapshot, currSnapshot]) => {
const prevProjects = prevSnapshot?.payload.data()?.projects || [];
const currProjects = currSnapshot.payload.data().projects || [];
// 筛选新增的ID
const addedIds = currProjects.filter(id => !prevProjects.includes(id));
// 筛选删除的ID(按需使用)
const removedIds = prevProjects.filter(id => !currProjects.includes(id));
return { addedIds, removedIds };
).subscribe(({ addedIds, removedIds }) => {