Каков наилучший способ структурирования данных по firebase?

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

У меня есть простой пример:

Есть заявители и заявки на мой проект. 1 заявитель может иметь несколько заявок. Как я могу связать эти 2 объекта на базе огня? Это работает как реляционная база данных? Или подход должен быть совершенно другим с точки зрения дизайна данных?

Ответ 1

UPDATE: теперь существует doc для структурирования данных. Также см. Этот отличный пост в Структуры данных NoSQL.

Основная проблема с иерархическими данными, в отличие от РСУБД, заключается в том, что она соблазняет вложение данных, потому что мы можем. Как правило, вы хотите в какой-то степени нормализовать данные (как и с SQL), несмотря на отсутствие заявлений и запросов на соединение.

Вы также хотите denormalize в местах, где эффективность чтения является проблемой. Это метод, используемый всеми крупномасштабными приложениями (например, Twitter и Facebook), и хотя он идет вразрез с нашими принципами DRY, он обычно является необходимой функцией масштабируемых приложений.

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

Основное различие между данными в реальном времени Firebase и средой SQL - это запрос данных. Нет простого способа сказать "ВЫБРАТЬ ПОЛЬЗОВАТЕЛЕЙ, ГДЕ X = Y" из-за характера данных в реальном времени (он постоянно меняется, очерчивает, согласовывает и т.д., Что требует более простой внутренней модели для проверки синхронизированных клиентов)

Простой пример, вероятно, установит вас в правильном состоянии ума, так вот:

/users/uid
/users/uid/email
/users/uid/messages
/users/uid/widgets

Теперь, поскольку мы находимся в иерархической структуре, если я хочу итерации адресов электронной почты пользователей, я делаю что-то вроде этого:

// I could also use on('child_added') here to great success
// but this is simpler for an example
firebaseRef.child('users').once('value')
.then(userPathSnapshot => {
   userPathSnapshot.forEach(
      userSnap => console.log('email', userSnap.val().email)
   );
})
.catch(e => console.error(e));

Проблема с этим подходом заключается в том, что я только что заставил клиента загрузить все пользователи messages и widgets тоже. Ничего, если ни одна из этих вещей не будет тысяча. Но большое дело для 10 тыс. Пользователей с более чем 5 тыс. Сообщений каждый.

Итак, теперь оптимальная стратегия для иерархической структуры в реальном времени становится более очевидной:

/user_meta/uid/email
/messages/uid/...
/widgets/uid/...

Дополнительным инструментом, который чрезвычайно полезен в этой среде, являются индексы. Создав индекс пользователей с определенными атрибутами, я могу быстро имитировать SQL-запрос, просто перебирая индекс:

/users_with_gmail_accounts/uid/email

Теперь, если я хочу, скажем, получить сообщения для пользователей Gmail, я могу сделать что-то вроде этого:

var ref = firebase.database().ref('users_with_gmail_accounts');
ref.once('value').then(idx_snap => {
   idx_snap.forEach(idx_entry => {
       let msg = idx_entry.name() + ' has a new message!';
       firebase.database().ref('messages').child(idx_entry.name())
          .on(
             'child_added', 
             ss => console.log(msg, ss.key);
          );
   });
})
.catch(e => console.error(e));

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

Ответ 2

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

Недавно Anant написал замечательный пост в блоге Firebase о денормализации ваших данных: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

Я действительно предлагаю хранить "идентификатор" каждой заявки в качестве ребенка каждого заявителя.

Ответ 3

Ваш сценарий выглядит как один ко многим в реляционном мире, в соответствии с вашим примером у заявителя есть много заявок. Если мы подойдем к Firebase Nosql, как это выглядит ниже. Он должен масштабироваться без проблем с производительностью. Вот почему нам нужна денормализация, как указано ниже.

applicants:{
applicant1:{
    .
    .
    applications:{
        application1:true,
        application3:true
    }
},
applicant2:{
    .
    .
    applications:{
        application2:true,
        application4:true
    }
}}

applications:{
application1:{
    .
    .
},
application2:{
    .
    .
},
application3:{
    .
    .
},
application4:{
    .
    .
}}