Angular Firestore get()返回空数据、snapshotChanges重复触发问题
解决方案
get()方法无法获取实际文档数据的修复方式
你调用get()返回的是Firestore原生的QuerySnapshot对象,不是直接的文档数组,不能直接通过下标读取内容,必须从对象的docs字段中解析每个文档快照的id和业务数据。
修复后的调用代码:
this.crud.getLastPedido().get().subscribe(querySnapshot => { // 处理集合为空的边界情况 if (querySnapshot.empty) { // 无历史数据时新文档ID可从1开始计数 return; } // limit(1)的查询结果只有1条文档,取docs数组第一个元素即可 const lastDocSnapshot = querySnapshot.docs[0]; const lastPedidoData = { cod: lastDocSnapshot.id, ...lastDocSnapshot.data() as Pedido }; // 后续ID+1生成新文档的逻辑写在这里 })
snapshotChanges回调重复触发的修复方式
snapshotChanges是实时监听接口,初始化时拉取本地缓存、同步服务端数据、后续集合内任何数据变更都会触发回调,所以会出现无数据变更也多次执行的情况。如果你的场景只需要查询一次最新文档、不需要后续实时更新,直接在管道中加take(1)操作符即可,拿到第一次返回的数据后会自动终止订阅,不会重复触发回调:
import { map, take } from 'rxjs/operators'; this.crud.getLastPedido().snapshotChanges() .pipe( take(1), // 仅取一次返回结果,自动取消监听 map(changes => changes.map(c => ({ cod: c.payload.doc.id, ...c.payload.doc.data() }))) ) .subscribe(data => { // 这里的业务逻辑只会执行一次 const lastPedido = data[0]; // 后续业务流程 })
如果需要保留实时监听能力,可以额外加distinctUntilChanged操作符做数据对比,只有查询到的最新文档内容实际发生变化时才执行业务逻辑,避免缓存、元数据变更导致的无效触发。
注意事项
不建议在Firestore中用手动查询最后ID+1的方式生成新文档ID:并发场景下(比如多个用户同时提交订单),多个请求会查到同一个最后ID,生成重复的自增ID导致数据覆盖。如果必须用连续数字ID,必须用Firestore事务runTransaction包装ID查询、自增、写入的全流程,保证原子性;普通场景直接用Firestore自动生成的随机字符串ID即可,不会出现重复问题。
内容的提问来源于stack exchange,提问作者Mariano Molina
相关产品推荐
相关产品推荐

