База данных Firebase - техника "Fan Out"

Я изучал базу данных Firebase для Android и понял, что он сохраняет свои данные следующим образом:

введите описание изображения здесь

Я не очень хорошо знаком с методами NoSQL и пытаюсь понять, почему мы должны упорствовать каждый объект post дважды - в posts и user_posts соответственно. В документации говорится, что этот подход называется "Fan Out", и я полностью согласен с тем, что было бы полезно получить доступ к сообщениям пользователей через простую конструкцию типа databaseReference.child("user-posts").child("<user_uid>"). Но зачем нам нужен posts node? Что делать, если нам нужно обновить некоторые сообщения - мы должны сделать это дважды?

// [START write_fan_out]
private void writeNewPost(String userId, String username, String title, String body) {
    // Create new post at /user-posts/$userid/$postid and at
    // /posts/$postid simultaneously
    String key = mDatabase.child("posts").push().getKey();
    Post post = new Post(userId, username, title, body);
    Map<String, Object> postValues = post.toMap();

    Map<String, Object> childUpdates = new HashMap<>();
    childUpdates.put("/posts/" + key, postValues);
    childUpdates.put("/user-posts/" + userId + "/" + key, postValues);

    mDatabase.updateChildren(childUpdates);
}
// [END write_fan_out]

Итак, мне интересно... когда этот подход может быть полезен, а когда нет? Предоставляет ли Firebase SDK какие-либо инструменты для синхронизации всех дубликатов при обновлении или удалении данных?


ОБНОВЛЕНИЕ: Вот объяснение получено от команды Firebase:

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

Это означает, что мы должны обновить сообщение в двух местах когда мы его обновляем. Это делает код немного уродливым, но поскольку запросы более распространены, чем лучше писать для оптимизации чтение данных.

Я подозреваю, что этот подход может выглядеть не совсем изящным, но, вероятно, это самый быстрый вариант для больших наборов данных, если вы выполняете SELECT чаще, чем UPDATE. Однако в некоторых случаях я предпочел бы использовать другие рекомендуемые здесь решения.

Ответ 1

Data Fan Out - отличный способ управления массивными объемами данных. Если вы не используете этот шаблон, у вас могут возникнуть серьезные проблемы масштабирования в будущем.

Что я вижу из структуры вашей базы данных, так это то, что вы сохраняете всю информацию о сообщении дважды, и это не очень хорошая практика. Вы хотите сохранить только ссылку на пост под другим node. Итак, у вас будет node с именем users-posts, который будет состоять из пользовательских ключей, и каждый из этих ключей будет иметь набор ключей сообщений со значением true. Чтобы сделать это более понятным:

введите описание изображения здесь

Таким образом, вы отслеживаете, какие записи написаны пользователем под users-posts node; а также пользователя, который написал каждое сообщение под posts node. Теперь вам может понадобиться получить список сообщений всех пользователей. Вам нужно будет синхронизировать на users-posts/USER_KEY/ node с получить ключи для всех сообщений, написанных пользователем, а затем получить дополнительную информацию о сообщении с помощью сообщения ключ, который вы только что получили.

Почему рекомендуется дизайн этой базы данных? Поскольку вы получаете гораздо меньше информации для каждой синхронизации (при использовании Firebase мы не отправляем запросы по-одному, поэтому я вызываю чтение синхронизацией). В вашем примере, если вы присоедините слушателя к user-posts/USER_KEY/, чтобы получить список всех сообщений, вы также попросите ВСЕ информацию о КАЖДОМ И КАЖДОМ, чтобы опубликовать их написал. При использовании подхода к отключению данных вы можете просто запросить информацию о должности, в которой вы нуждаетесь, потому что у вас уже есть ключ от сообщений.

Ответ 2

По-моему, это не очень хороший подход, так как вам нужно синхронизировать эти данные, и Firebase не предоставляет никаких инструментов для синхронизации дубликатов. Хорошим подходом было бы хранить только ключ в user-posts.

Я предлагаю прочитать это, очень интересно понять, как структурировать данные: https://www.firebase.com/docs/web/guide/structuring-data.html