如何阻止斜杠分割Firebase数据库子节点
解决Firebase数据库中子节点含斜杠的存储问题
我开发的学生注册应用允许使用学号(格式如17/csc/001)注册,原本计划将学号作为Firebase数据库引用的子节点保存,但Firebase会将学号中的斜杠解析为层级结构,导致存储结果不符合预期。
期望存储结构
"Registration Numbers": { "17/csc/001": { "registrationNumber": "17/csc/001" } }
实际存储结构
"Registration Numbers": { "17": { "CSC": { "001": { "registrationNumber": "17/CSC/001" } } } }
当前实现代码
void addRegistrationNumber(){ progressBar.setVisibility(View.VISIBLE); String regNumber = editText.getText().toString(); final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference(); databaseReference.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { if (snapshot.child("Registration Numbers").child(regNumber).exists()){ progressBar.setVisibility(View.GONE); showMessage("Error","You have Already Added this Registration Number"); }else { HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put("registrationNumber",regNumber); databaseReference.child("Registration Numbers").child(regNumber).updateChildren(hashMap) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()){ progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Registration Number Added Successfully", Toast.LENGTH_SHORT).show(); }else { progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Error Occurred, Please try Again", Toast.LENGTH_SHORT).show(); } } }); } } @Override public void onCancelled(@NonNull DatabaseError error) { progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Database error "+error.toString(), Toast.LENGTH_SHORT).show(); } }); }
解决方案
方法1:替换学号中的斜杠
将学号里的/替换为Firebase允许的字符(如_或-),用替换后的字符串作为节点键,同时在数据中保留原始学号。修改后的代码如下:
void addRegistrationNumber(){ progressBar.setVisibility(View.VISIBLE); String regNumber = editText.getText().toString(); // 替换斜杠为下划线,生成合法的节点键 String safeRegNumber = regNumber.replace("/", "_"); final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference(); databaseReference.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { if (snapshot.child("Registration Numbers").child(safeRegNumber).exists()){ progressBar.setVisibility(View.GONE); showMessage("Error","You have Already Added this Registration Number"); }else { HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put("registrationNumber", regNumber); // 保留原始学号 databaseReference.child("Registration Numbers").child(safeRegNumber).updateChildren(hashMap) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()){ progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Registration Number Added Successfully", Toast.LENGTH_SHORT).show(); }else { progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Error Occurred, Please try Again", Toast.LENGTH_SHORT).show(); } } }); } } @Override public void onCancelled(@NonNull DatabaseError error) { progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Database error "+error.toString(), Toast.LENGTH_SHORT).show(); } }); }
修改后的存储结构:
"Registration Numbers": { "17_csc_001": { "registrationNumber": "17/csc/001" } }
方法2:使用Firebase自动生成的节点ID
如果不需要将学号作为节点键,可以用Firebase的push()方法生成唯一ID作为节点键,通过字段值来存储和查询学号:
void addRegistrationNumber(){ progressBar.setVisibility(View.VISIBLE); String regNumber = editText.getText().toString(); final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Registration Numbers"); // 通过字段值查询学号是否已存在 databaseReference.orderByChild("registrationNumber").equalTo(regNumber).addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { if (snapshot.exists()){ progressBar.setVisibility(View.GONE); showMessage("Error","You have Already Added this Registration Number"); }else { // 生成唯一节点ID String pushId = databaseReference.push().getKey(); HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put("registrationNumber", regNumber); databaseReference.child(pushId).updateChildren(hashMap) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()){ progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Registration Number Added Successfully", Toast.LENGTH_SHORT).show(); }else { progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Error Occurred, Please try Again", Toast.LENGTH_SHORT).show(); } } }); } } @Override public void onCancelled(@NonNull DatabaseError error) { progressBar.setVisibility(View.GONE); Toast.makeText(AdminAddOrRemoveARegistrationNumberActivity.this, "Database error "+error.toString(), Toast.LENGTH_SHORT).show(); } }); }
这种方式的存储结构:
"Registration Numbers": { "-N123abcXYZ": { "registrationNumber": "17/csc/001" } }
方案选择建议
- 方法1适合需要通过学号快速定位节点的场景,查询时只需将输入的学号做相同替换即可。
- 方法2适合不需要直接用学号作为节点标识的场景,查询时需通过
orderByChild("registrationNumber")进行过滤。
内容的提问来源于stack exchange,提问作者Ukeme Elijah
相关产品推荐
相关产品推荐

