Який найкращий спосіб структурування даних на базі даних?


111

Я новачок у firebase і хочу знати, який найкращий спосіб структурування даних на ньому.

Я маю простий приклад:

У моєму проекті є Заявники та Заявки. 1 заявник може мати кілька заявок. Як я можу співвідносити ці 2 об’єкти на firebase? Це працює як реляційна база даних? Або підхід повинен бути абсолютно іншим щодо дизайну даних?

Відповіді:


137

ОНОВЛЕННЯ : Зараз існує документ про структурування даних . Також дивіться цей чудовий пост про структури даних NoSQL .

Основна проблема з ієрархічними даними, на відміну від RDBMS, полягає в тому, що це спокуса вкладати дані, оскільки ми можемо. Як правило, ви хочете певною мірою нормалізувати дані (як і в SQL), незважаючи на відсутність заяв і запитів приєднання.

Ви також хочете денормалізувати у місцях, де ефективність читання викликає занепокоєння. Це методика, яка використовується всіма масштабними програмами (наприклад, 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));

Я запропонував деякі подробиці в іншому дописі про денормалізацію даних, тому перевірте і їх . Я бачу, що Френк вже опублікував статтю Ананта, тому я не повторюю це тут, але це також чудове прочитання.


Дякую за це розуміння Като!
бункер

2
В даний час. Погляди у версії Firefox v2 містять чудові можливості для автоматизації цього процесу.
Kato

Усвідомлюючи, що я відроджую тут стару нитку коментарів, але я намагаюся знайти більш сучасне рішення. Це все-таки найкращий підхід? тобто отримання всіх users_with_gmail_accounts, а потім запуск forEach?
owiewio

48

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

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

Я дійсно пропоную зберігати "посвідчення" кожної заяви як дитина кожного заявника.


Дякую Френку! Це справді корисно. Саме те, що я шукав!
бункер

4

Ваш сценарій виглядає як один до багатьох у реляційному світі, згідно з вашим прикладом заявник має багато застосувань. Якщо ми підійдемо до firebase nosql так, це виглядає нижче. Він повинен масштабуватися без будь-яких проблем з продуктивністю. Ось чому нам потрібна денормалізація, як зазначено нижче.

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

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

Добре, але я маю на увазі, як ми можемо створити цю структуру з Swift або з будь-якого місця за допомогою Firebase SDK? Також як ми можемо перевірити, що нові дані, додані до вузла програм, насправді існують у списку програм за допомогою правил перевірки Firebase?
Tommie C.

@prateep, Добрий приклад. Але тут проблема полягає в тому, коли я видаляю програми / application1, де application1 є дочірнім для деяких заявників. Якщо я спробую отримати доступ до заявників / заявок1, яких там немає. тож вам потрібно оновити індекси в обох місцях, як application1: {заявники: {заявник1: правда} ...}, тому тепер, коли я видаляю applicationantion1, я повинен перевірити це дочірні заявники та оновити дочірній вузол заявників на додаток. :)
Satish Sojitra
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.