База данных Firebase - Обновление ограниченного значения только для одного пользователя - PullRequest
0 голосов
/ 23 сентября 2018

Я использую базу данных Firebase Realtime в приложении для Android, приложение содержит статьи, и я хочу добавить Количество просмотров к статьям для всех пользователей приложения.

База данных содержит дочерний элемент (ViewsCount)его значение (это число) Мне нужно, чтобы это значение обновлялось (увеличивалось на 1) каждый раз, когда статья просматривается новым пользователем (концепция аналогична просмотрам видео на YouTube)

Пользователь должен проходить аутентификацию анонимнообновить значение, но не должно быть в состоянии сделать это более одного раза.

Я встроил логику в приложение, чтобы сделать это, и прекрасно работает.Но я боюсь, что кто-то попытается подключиться к базе данных за пределами моего приложения (используя собственный код) и продолжит увеличивать значение.

Мои текущие правила безопасности:

"ViewsCount"
{
  ".write": "newData.exists() && auth!==null",
  ".validate" "newData.val()===data.val()+1"
}
"users": { 
  "$user_id": { 
    ".write": "auth.uid===$user_id", 
    ".read": "auth.uid===$user_id ",
  }
}

Есть ли способ ограничить обновление этого значения только один раз для пользователя с помощью правил безопасности?Ошибка:

Обновление: скриншот с симулятора Структура базы данных

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Это правила безопасности, которые работали в случае, если кто-то еще имеет такую ​​же проблему:

{"rules": {
"views": { 
  ".write": "auth != null",
".validate": "newData.hasChildren(['ViewsCount', 'viewedBy'])",

"ViewsCount": {
".read": "auth != null",
".validate":"data.parent().child('viewedBy').child(auth.uid).exists()== false"
},

"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
&& newData.val()===true"}},

     },
0 голосов
/ 24 сентября 2018

Конечно, но вам придется проделать дополнительную работу.Первым делом нужно отследить в базе данных, кто уже просматривал каждую статью.Например, сохраните список своих 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, чтобы увидеть, был ли текущий пользователь уже посчитан, прежде чем пытаться подсчитать его.Но в любом случае: с этими правилами каждый пользователь может рассчитывать только один раз.


Обновление : вот как я тестировал эти правила в симуляторе:

Firebase Realtime Database rules simulator

И это JSON, с которым я тестировал:

"52469568": {
  "ViewsCount": 10,
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...