【问题标题】:Check value already exists or not in Firebase?检查值是否已存在于 Firebase 中?
【发布时间】:2020-12-30 20:16:39
【问题描述】:

这是我的 Firebase 数据库结构。我想检查用户将要进入的新大学已经存在或不存在的大学?问题是大学节点有随机密钥所以我不知道如何检查大学的有效性? 如果大学已经存在就不要再写了

【问题讨论】:

标签: java android firebase android-layout firebase-realtime-database


【解决方案1】:

在您当前的结构中,您可以使用如下查询来检查大学名称作为 /Universities 下的值存在的频率:

String name = "Comsats";
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Universities");
ref.orderByValue().equalTo(name).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        Log.i("Firebase", "There are "+dataSnapshot.getChildrenCount()+" universities named "+name);
        for (DataSnapshot universitySnapshot: dataSnapshot.getChildren()) {
            Log.i("Firebase", universitySnapshot.getKey+": "+universitySnapshot.getValue(String.class));
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException();
    }
}

或者只是为了检查它是否存在,这会稍微简单/更快:

ref.orderByValue().equalTo(name).limitToFirst(1).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        if (dataSnapshot.exists()) {
            Log.i("Firebase", "University "+name+" already exists");
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException();
    }
}

如果您使用上述方法然后添加大学,您最终会遇到竞争条件。当一个客户端检查名称是否已经存在时,另一个客户端可能正在添加它。由于不能保证这些操作按您希望的顺序进行,因此您仍然可能最终得到两所同名的大学。

防止这种情况的唯一方法是使用大学名称作为节点的*,而不是作为值。您的结构将变为:

"Universities": {
  "University of Haripu": true,
  "Comsats": true,
  "UET": true
}

节点键在特定位置保证是唯一的,因为无法插入第二个同名的子节点。因此,使用这种结构,您可以自动保证数据结构中的唯一性要求。

true 值在上述结构中没有特定含义,只是因为 Firebase 无法存储没有值的键。如果你有更有意义的价值,你也可以使用它。事实上,你可能不得不这样做......


Firebase 有一些字符不允许出现在节点键中,而这些字符允许出现在值中。如果您的值可能包含这样的值,则您需要对用户输入的值执行一些编码,并将其转换为您为大学存储的密钥。

两种常见的编码是:

  1. 从字符串中删除违规字符。
  2. 使用字符串的哈希码。

第一种方法会导致更多可识别的键,所以我将在这里使用它。在实践中,第二种方法通常在代码中更好更简单,因为如今散列是相当标准的功能,而其他编码可能会为您的用例或 Firebase 定制。

在这两种情况下,您都需要存储用户输入的实际值。所以说空格和大写字符不允许用于键(它们都是都允许的,所以这只是一个说明性的例子),你最终会得到:

"Universities": {
  "universityofharipu": "University of Haripu",
  "comsats": "Comsats",
  "uet": "UET"
}

保证唯一性之前已经讨论过很多次了,所以我推荐看看这些:

【讨论】:

  • 是的,它有效。我改变了职位......我把大学作为关键,但有一个小问题......我想计算在数据库中注册的大学的数量,当同一所大学再次调用时,他们调用相同的键值并更改编号,有什么解决办法吗?
  • 这是一个新问题,但听起来像:1)您需要在每个键下存储名称和计数,2)然后使用 ServerValue.increment(1) 增加值。如果您在完成这项工作时遇到问题,我建议您发布一个新问题,说明您尝试过的内容以及遇到的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多