Firestore双查询计算返回undefined或过慢问题排查求助
问题:Firestore异步查询返回undefined或加载缓慢,无法正确计算差值
我尝试获取两个Firestore查询结果并进行差值计算,但查询操作要么速度极慢,要么返回undefined,仅在刷新应用后偶尔能正常显示数值。第一个查询用于统计集合'announcements'中'active'字段为true的文档数量;第二个查询统计该集合中'active'为true且'hasread.{user.uid}'为true的文档数量,最终计算两者的差值。以下是我使用的代码:
export default class Home extends React.Component { constructor(props) { super(props) this.gettingAmount = false; this.unsubscribe = null; this.announce = firebase.firestore().collection('announcements'); this.state = { newAnnouncements: 0, } } componentDidMount() { this.gettingAmount = true; let countHasRead; let countAnnounce; this.unsubscribe = firebase.auth().onAuthStateChanged((user) => { if (user) { this.announce .where('active', '==', true) .get() .then(snapshot => { countAnnounce = snapshot.size; }); this.announce .where('active', '==', true) .where('hasread.' + user.uid, '==', true) .get() .then(snapshot => { countHasRead = snapshot.size; }) .catch(err => { console.log('Error getting documents', err); }); setTimeout(() => { console.log('second', countAnnounce, countHasRead); if (this.gettingAmount) { this.gettingAmount = false; this.setState({newAnnouncements: countAnnounce - countHasRead}); AsyncStorage.setItem('newAnnouncements', JSON.stringify(countAnnounce - countHasRead)); } }, 1000); } }); } }
console.log('second')输出的countAnnounce和countHasRead时常为undefined,或加载极慢才能显示数值。请问我哪里操作有误?为何会返回undefined?恳请帮助。
解决方案
核心问题分析
你的代码最大的问题是错误处理了异步操作的执行顺序:
- Firestore的
get()方法是异步的,它返回一个Promise,只有当Promise被resolve后才能拿到查询结果。 - 你用固定1秒的
setTimeout来等待结果,这完全不可靠——网络延迟、数据量大小都会影响查询完成的时间,1秒内没完成的话,countAnnounce和countHasRead就还是初始的undefined状态;偶尔能正常显示只是刚好那次查询在1秒内完成了,属于碰运气。
修复后的代码
我们可以用Promise.all()来并行执行两个异步查询,确保两个查询都完成后再计算差值、更新状态:
export default class Home extends React.Component { constructor(props) { super(props); this.unsubscribe = null; this.announce = firebase.firestore().collection('announcements'); this.state = { newAnnouncements: 0, }; } componentDidMount() { this.unsubscribe = firebase.auth().onAuthStateChanged(async (user) => { if (user) { try { // 并行执行两个查询,等待两者都完成 const [announceSnapshot, hasReadSnapshot] = await Promise.all([ this.announce.where('active', '==', true).get(), this.announce.where('active', '==', true).where(`hasread.${user.uid}`, '==', true).get() ]); const countAnnounce = announceSnapshot.size; const countHasRead = hasReadSnapshot.size; const newAnnouncements = countAnnounce - countHasRead; console.log('查询结果', countAnnounce, countHasRead); this.setState({ newAnnouncements }); await AsyncStorage.setItem('newAnnouncements', JSON.stringify(newAnnouncements)); } catch (err) { console.error('获取文档失败', err); } } else { // 用户登出时重置状态 this.setState({ newAnnouncements: 0 }); await AsyncStorage.setItem('newAnnouncements', '0'); } }); } componentWillUnmount() { // 清理auth状态监听,避免内存泄漏 if (this.unsubscribe) { this.unsubscribe(); } } }
额外优化建议
- 实时更新数据:如果需要当公告数据或已读状态变化时自动更新未读数量,可以把
get()换成onSnapshot(),这样能监听数据的实时变化:
// 示例:实时监听active公告 const unsubscribeAnnounce = this.announce.where('active', '==', true).onSnapshot(snapshot => { // 这里处理实时更新的逻辑 }); // 记得在componentWillUnmount里清理这个监听
- 避免重复查询:如果两个查询的过滤条件大部分重复,且数据量不大,可以考虑获取所有active的公告后,在客户端统计已读数量(数据量大的话还是推荐用Firestore查询,更高效)。
内容的提问来源于stack exchange,提问作者udarts
相关产品推荐
相关产品推荐

