当然可以,但您必须做一些额外的工作。首先是在数据库中跟踪谁已经查看了每篇文章。例如,保留他们的 UID 列表,如下所示:
viewedBy: {
uidOfKarim: true,
uidOfPuf: true
}
现在,当有人查看文章时,他们会将其 UID 写入 viewedBy,同时增加该文章的查看次数。在代码中可以很简单:
DatabaseReference countRef = FirebaseDatabase.getInstance().getReference("ViewsCount");
countRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String uid = FirebaseAuthentication.getCurrentUser().getUid();
Long newCount = dataSnapshot.getValue(Long.class) + 1;
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("viewedBy/"+uid, true);
updates.put("ViewsCount", newCount);
}
@Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
}
所以这段代码将用户的UID和新的视图计数发送到数据库。现在我们将安全性更新为仅在 UID 尚未存储且计数增加 1 时才接受写入操作:
"viewedBy": {
"$user_id": {
".validate": "
auth.uid===$user_id && !data.exists() && newData.exists() &&
newData.parent().parent().child('ViewsCount').val() === data.parent().parent().child('ViewsCount').val()+1
"
}
},
语法有点长,因为它同时检查ViewsCount 和ViewedBy 数据。只有当它增加 1 并且来自尚未计数的用户时,写入才会成功。如果它们之前被计算过,或者不加 1,则写入被拒绝。
这里有一个极端情况:如果多个用户几乎同时查看,他们的一个写入可能会被拒绝,因为他们实际上并没有增加值:
user1 user2 database
| | |
read_count -------------------> |
| | |
| read_count --------> |
| | |
| <------------------- 2 |
| | |
| | <------------ 2 |
| | |
set_count 3 -------------------> |
| | |
| set_count --------> |
| | |
| <------------------- ok |
| | |
| | <------------ ACCESS |
| | DENIED |
| | |
在这种情况下,您应该重试更新操作,读取新值并据此确定正确的计数。这实际上是 Firebase 事务在幕后的工作方式。或者,您可以先阅读viewedBy 以查看当前用户是否已被计算在内,然后再尝试计算它们。但无论哪种方式:根据这些规则,每个用户只能算一次。
更新:这是我在模拟器中测试这些规则的方式:
这是我测试的 JSON:
"52469568": {
"ViewsCount": 10,
}