使用Firebase Push ID时,如何检查date、timeIn、timeOut已有数据?
解决Firebase预订数据重复检查的问题
我明白你现在遇到的困扰了——你想在添加新的场地预订前,检查是否已经存在相同日期、开始时间和结束时间的记录,但当前的代码逻辑完全走偏了,因为你是在直接检查Firebase根节点下是否有以date/timeIn/timeOut值命名的子节点,而这些值其实是每个预订记录内部的字段,不是节点的Push ID或键名。
问题出在哪?
你的代码里dataSnapshot.child(dateinput.getText().toString()).exists()这种写法,是在判断根节点下是否有一个直接子节点的键等于你输入的日期,但实际上你的数据结构应该是这样的(假设CourtBookingDatabase指向预订记录的根):
CourtBookings - PushID1 - courtType: "..." - date: "2024-05-20" - timeIn: "09:00" - timeOut: "10:00" - purpose: "..." - PushID2 - ...
所以你直接查根节点的child是找不到对应字段值的,必须通过**查询(Query)**来过滤出符合字段条件的记录。
正确的解决方案
我们需要用Firebase的查询功能,组合过滤date、timeIn、timeOut三个字段的匹配记录,然后判断是否存在这样的记录:
修改后的代码示例
private void addCourtBooking() { // 获取要检查的字段值 String checkDate = dateinput.getText().toString(); String checkTimeIn = timeStartSpinner.getSelectedItem().toString(); String checkTimeOut = timeEndSpinner.getSelectedItem().toString(); // 构建查询:查找date、timeIn、timeOut都匹配的记录 Query existingBookings = CourtBookingDatabase .orderByChild("date") .equalTo(checkDate) .orderByChild("timeIn") .equalTo(checkTimeIn) .orderByChild("timeOut") .equalTo(checkTimeOut); existingBookings.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if (dataSnapshot.exists()) { // 存在重复记录 Toast.makeText(getApplicationContext(), "该时段已被预订", Toast.LENGTH_LONG).show(); } else { // 没有重复,添加新预订 String uCourtType = txtCourtType.getText().toString(); String uPurpose = sp.getSelectedItem().toString(); Map<String, Object> courtBookingInfo = new HashMap<>(); courtBookingInfo.put("courtType", uCourtType); courtBookingInfo.put("purpose", uPurpose); courtBookingInfo.put("date", checkDate); courtBookingInfo.put("timeIn", checkTimeIn); courtBookingInfo.put("timeOut", checkTimeOut); // 用push()生成唯一Push ID,避免覆盖已有数据 CourtBookingDatabase.push().setValue(courtBookingInfo); Toast.makeText(getApplicationContext(),"预订成功", Toast.LENGTH_LONG).show(); } } @Override public void onCancelled(DatabaseError databaseError) { // 处理查询取消/错误 Toast.makeText(getApplicationContext(), "查询失败:" + databaseError.getMessage(), Toast.LENGTH_LONG).show(); } }); }
关键注意事项
- 添加复合索引:因为我们同时对三个字段进行排序和过滤,需要在Firebase控制台的数据库规则中添加对应的复合索引,否则会收到性能警告或查询失败。索引规则示例:
{ "rules": { "CourtBookings": { ".indexOn": ["date", "timeIn", "timeOut"] } } } - 使用
addListenerForSingleValueEvent:相比addValueEventListener,单次监听更适合这种一次性的检查操作,避免不必要的实时更新监听。 - 用
push()生成节点:原来的setValue()会直接覆盖根节点的数据,这是非常危险的!必须用push()生成唯一的Push ID,把新预订作为子节点添加,这样才不会丢失已有数据。
内容的提问来源于stack exchange,提问作者Fatinnba
相关产品推荐
相关产品推荐

