如何用Firebase Functions的.before/.after监听Map对象.onUpdate变化及问题解决
Firestore onUpdate处理Map字段时逻辑异常问题
我在Firestore的.onUpdate函数里用snap.before.data()和snap.after.data()处理Map类型字段时遇到了逻辑异常——明明只更新了mark这个Map对象,却同时触发了strat和mark相关的函数逻辑。我知道.onUpdate不会按字段值触发,但可以通过对比before和after的字段变化来判断,想确认这种方式是否适用于文档的顶级Map对象(strat和mark都是文档的顶级字段),相关代码如下:
export const BARupdate = functions.firestore .document('inputs/{inputUserID}') .onUpdate(async (snap, context) => { functions.logger.log('bar update is running'); // .after should represent after changes const userInfo: any = { ...snap.after.data(), userID: snap.after.id, }; const newValue = snap.after.data(); const oldValue = snap.before.data() if (userInfo['strat'] !== undefined) { if (newValue.strat !== oldValue.strat){ console.log('snap same strat? NO') const stratData = userBusinessInfo['strat']; const userID = userBusinessInfo?.userID; } else { console.log('STRAT IS THE SAME') } return } if (userBusinessInfo['mark'] !== undefined) { if (newValue.mark !== oldValue?.mark){ console.log('snap same mark? NO') const markData = userInfo['mark']; const userID = userInfo?.userID; } else { console.log('MARK IS THE SAME') } return } });
问题分析与解决方法
核心问题:对象引用对比不生效
你现在用newValue.strat !== oldValue.strat对比Map对象,本质是对比两个对象的内存引用地址,而非实际内容。Firestore每次返回的.data()都是新的对象实例,哪怕Map内容完全没变化,引用地址也不一样,这会导致判断永远为true,只要strat字段存在就会触发对应逻辑。这种对比方式不适用于Map对象的内容校验,必须改成对比对象的实际内容。
其他代码问题
- 未定义变量引用:代码中多次使用
userBusinessInfo,但这个变量从未定义,应该统一替换为已声明的userInfo或newValue。 - 逻辑终止顺序错误:第一个
if块末尾直接return,会导致无论strat是否变化,函数都会终止,后续mark的判断逻辑根本无法执行(和你描述的“同时触发两个逻辑”矛盾,可能是代码粘贴时的错误)。
修正后的代码示例
import { deepEqual } from 'lodash'; // 可以用lodash的深对比,或者自己实现深对比函数 export const BARupdate = functions.firestore .document('inputs/{inputUserID}') .onUpdate(async (snap, context) => { functions.logger.log('bar update is running'); const userInfo: any = { ...snap.after.data(), userID: snap.after.id, }; const newValue = snap.after.data(); const oldValue = snap.before.data(); // 检查strat字段是否存在且内容变化 if (newValue.strat !== undefined) { // 用深对比判断Map内容是否变化 if (!deepEqual(newValue.strat, oldValue?.strat)) { console.log('strat内容已变更'); const stratData = userInfo['strat']; const userID = userInfo.userID; // 执行strat相关逻辑 } else { console.log('strat内容未变化'); } } // 检查mark字段是否存在且内容变化 if (newValue.mark !== undefined) { if (!deepEqual(newValue.mark, oldValue?.mark)) { console.log('mark内容已变更'); const markData = userInfo['mark']; const userID = userInfo.userID; // 执行mark相关逻辑 } else { console.log('mark内容未变化'); } } });
替代方案:自己实现深对比函数
如果不想引入lodash,可以自己写一个简单的深对比函数(仅针对Map/对象类型):
function isDeepEqual(obj1: any, obj2: any): boolean { // 先对比引用 if (obj1 === obj2) return true; // 检查是否都是对象且不为null if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) { return false; } // 获取键名数组 const keys1 = Object.keys(obj1); const keys2 = Object.keys(obj2); // 键数量不同直接返回false if (keys1.length !== keys2.length) return false; // 递归对比每个键的值 for (const key of keys1) { if (!keys2.includes(key) || !isDeepEqual(obj1[key], obj2[key])) { return false; } } return true; }
内容的提问来源于stack exchange,提问作者TSH
相关产品推荐
相关产品推荐

