Firebase(Unity) RTDB事务更新节点数据异常问题
Unity Firebase RTDB RunTransaction 节点覆盖问题
问题现象
使用RunTransaction更新RTDB节点时,预期新增key_a/key_b/key_c并保留原有key_d,但真机测试中节点被完全覆盖,key_d丢失。编辑器测试和RTDB规则playground中表现符合预期(新键添加、旧键保留)。
安全规则设置了.validate": "newData.hasChildren(['key_a', 'key_b', 'key_c', 'key_d'])",该规则在编辑器中有效,但真机上无法阻止不符合要求的数据写入。
代码片段
初始更新代码:
Dictionary<string, object> newData = new Dictionary<string, object>(); newData["key_a"] = "val_a"; newData["key_b"] = "val_b"; newData["key_c"] = "val_c"; mutableData.Value = newData;
完整交易代码:
db_reference .Child("node") .RunTransaction(RunTransaction) .ContinueWithOnMainThread(task => { if (task.Exception != null) { Debug.Log("Transaction exception."); } else if (task.IsCompleted) { Debug.Log("Transaction complete."); } }); TransactionResult RunTransaction(MutableData mutableData) { List<object> data = mutableData.Value as List<object>; if (data != null) { Dictionary<string, object> newData = new Dictionary<string, object>(); newData["key_a"] = "val_a"; newData["key_b"] = "val_b"; newData["key_c"] = "val_c"; mutableData.Value = newData; // 节点被覆盖的核心问题点 } else { Dictionary<string, object> newData = new Dictionary<string, object>(); newData["key_a"] = "val_a"; newData["key_b"] = "val_b"; newData["key_c"] = "val_c"; newData["key_d"] = "val_d"; mutableData.Value = newData; } return TransactionResult.Success(mutableData); }
环境信息
- Unity: 2021.3.9f1
- Firebase: 9.4.0
问题原因
- 类型转换错误:代码中错误地将
mutableData.Value转为List<object>,但RTDB的对象节点实际存储为Dictionary<string, object>。不同平台(编辑器/真机)的SDK解析行为不一致,导致真机上进入错误分支,直接写入不含key_d的新字典。 - 节点完全覆盖:直接将
mutableData.Value赋值为全新的Dictionary,会替换整个节点数据,而非在原有数据基础上更新。
解决方案
修改RunTransaction方法,正确获取原有节点数据并进行增量更新:
TransactionResult RunTransaction(MutableData mutableData) { // 正确解析原有节点数据为Dictionary Dictionary<string, object> existingData = mutableData.Value as Dictionary<string, object>; Dictionary<string, object> newData; if (existingData != null) { // 基于原有数据创建新字典,保留所有旧键值 newData = new Dictionary<string, object>(existingData); } else { // 节点不存在时初始化完整数据 newData = new Dictionary<string, object>(); newData["key_d"] = "val_d"; } // 增量更新需要修改的键 newData["key_a"] = "val_a"; newData["key_b"] = "val_b"; newData["key_c"] = "val_c"; mutableData.Value = newData; return TransactionResult.Success(mutableData); }
说明
- 该修改会保留原有节点的所有键值,仅更新指定的
key_a/key_b/key_c,确保key_d不会丢失。 - 修正类型转换后,编辑器和真机的行为将保持一致,安全规则也会正常验证
newData包含所有要求的子节点。
内容的提问来源于stack exchange,提问作者FDev
相关产品推荐
相关产品推荐

