Firebase数据库中如何判断记录存在性并执行更新或新增操作?
Firebase 数据同步问题求助
我的Firebase数据库结构如下:
{ "database": [ null, { "_location_id": 1, "_location_address": "ABC", "_location_county": "CS", "_location_description": "N/A", "_location_image": "" }, { "_location_id": 2, "_location_address": "DEF", "_location_county": "BC", "_location_description": "djbkdbksbk", "_location_image": "" } ] }
需求
判断Firebase中是否存在指定_location_id(例如2)的记录:
- 若存在,与本地数据库记录对比,一致则跳过,不一致则更新
- 若不存在则新增记录
尝试的Java代码(未成功)
MESSAGE_REFERENCE.orderByKey().equalTo(row.get(0).toString()).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if(dataSnapshot.exists()){ //verify if need to do update text1.setText("ID exist: " + row.get(0).toString()); // row是从本地数据库读取的记录 } else { text1.setText("ID not exist: " + row.get(0).toString()); } } @Override public void onCancelled(DatabaseError databaseError) { } });
作为业余开发者,寻求相关技术建议。
问题分析与解决方案
1. 核心问题:数据库结构不匹配查询需求
你当前用数组存储数据,Firebase数组有两个致命问题:
- 数组索引和业务ID(
_location_id)不绑定,删除中间记录会导致索引混乱 orderByKey()只能按数组的索引(0、1、2)查询,无法直接定位业务字段_location_id,这是代码失效的根本原因
最优方案:改成键值对结构
用_location_id作为节点的key,查询和操作效率会大幅提升,结构如下:
{ "database": { "1": { "_location_id": 1, "_location_address": "ABC", "_location_county": "CS", "_location_description": "N/A", "_location_image": "" }, "2": { "_location_id": 2, "_location_address": "DEF", "_location_county": "BC", "_location_description": "djbkdbksbk", "_location_image": "" } } }
2. 修复后的代码逻辑
基于键值对结构,直接定位目标节点完成查询、对比、更新/新增操作:
// 从本地获取目标ID,转成字符串作为Firebase节点key String targetId = row.get(0).toString(); DatabaseReference locationRef = MESSAGE_REFERENCE.child(targetId); // 用单次监听避免重复触发(如果不需要实时同步) locationRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if(dataSnapshot.exists()){ // 读取Firebase中的记录(需要对应实体类) Location firebaseLoc = dataSnapshot.getValue(Location.class); // 读取本地数据库的对应记录 LocalLocation localLoc = getLocalLocationById(targetId); // 对比所有字段,判断是否需要更新 if(!isLocationsEqual(firebaseLoc, localLoc)){ locationRef.setValue(localLoc); text1.setText("ID " + targetId + " 已更新"); } else { text1.setText("ID " + targetId + " 无需更新"); } } else { // 新增记录,直接上传本地数据 LocalLocation newLoc = getLocalLocationById(targetId); locationRef.setValue(newLoc); text1.setText("ID " + targetId + " 已新增"); } } @Override public void onCancelled(DatabaseError databaseError) { // 处理错误,比如打印日志 Log.e("FirebaseError", databaseError.getMessage()); } });
3. 辅助代码示例
需要定义实体类和字段对比方法:
// 对应Firebase数据结构的实体类,必须有空构造函数 public class Location { public int _location_id; public String _location_address; public String _location_county; public String _location_description; public String _location_image; public Location() {} } // 对比两个Location对象的所有字段是否一致 private boolean isLocationsEqual(Location firebaseLoc, LocalLocation localLoc) { return firebaseLoc._location_id == localLoc._location_id && firebaseLoc._location_address.equals(localLoc._location_address) && firebaseLoc._location_county.equals(localLoc._location_county) && firebaseLoc._location_description.equals(localLoc._location_description) && firebaseLoc._location_image.equals(localLoc._location_image); }
4. 若坚持使用数组结构的临时修复
如果不想修改数据库结构,需要改用orderByChild()按_location_id查询,但数组结构的弊端依然存在:
int targetId = Integer.parseInt(row.get(0).toString()); MESSAGE_REFERENCE.orderByChild("_location_id").equalTo(targetId) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if(dataSnapshot.exists()){ // 注意:可能返回多个重复ID的记录,需要遍历处理 for(DataSnapshot snap : dataSnapshot.getChildren()){ Location firebaseLoc = snap.getValue(Location.class); // 后续对比逻辑同上 } } else { // 新增记录需要用push()或手动找索引,不推荐 } } @Override public void onCancelled(DatabaseError databaseError) {} });
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

