Coba Cloud Firestore: Lihat database yang skalabel dan fleksibel dari Firebase dan Google Cloud Platform. Pelajari Cloud Firestore lebih lanjut.

Membuat Struktur Database Anda

Panduan ini mencakup beberapa konsep utama dalam arsitektur data dan praktik terbaik untuk merancang struktur data JSON dalam Firebase Realtime Database Anda.

Membuat database yang terstruktur dengan baik membutuhkan perencanaan yang matang. Yang terpenting, Anda harus merencanakan bagaimana data akan disimpan dan diambil kembali untuk membuat proses tersebut menjadi semudah mungkin.

Metode perancangan struktur data: dengan pohon JSON

Semua data Firebase Realtime Database disimpan sebagai objek JSON. Anda dapat menganggap database sebagai pohon JSON yang dihosting di cloud. Tidak seperti database SQL, database tersebut tidak memiliki tabel atau catatan. Ketika Anda menambahkan data ke pohon JSON, data tersebut akan menjadi node di struktur JSON yang ada dengan kunci terkait. Anda dapat memasukkan kunci sendiri, misalnya ID pengguna atau nama semantik, atau kunci dapat disediakan untuk Anda menggunakan childByAutoId.

Jika Anda membuat kunci sendiri, kunci tersebut harus berenkode UTF-8, berukuran maksimum 768 byte, dan tidak boleh berisi karakter ., $, #, [, ], /, atau karakter kontrol ASCII 0-31 atau 127. Anda juga tidak dapat menggunakan karakter kontrol ASCII dalam nilai-nilai itu sendiri.

Misalnya, bayangkan sebuah aplikasi chat yang memungkinkan pengguna untuk menyimpan profil dasar dan daftar kontak. Profil pengguna biasanya terletak pada suatu lokasi, misalnya /users/$uid. Pengguna alovelace mungkin memiliki entri database yang terlihat seperti ini:

{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      "contacts": { "ghopper": true },
    },
    "ghopper": { ... },
    "eclarke": { ... }
  }
}

Meskipun database ini menggunakan pohon JSON, data yang tersimpan di database dapat digambarkan sebagai jenis bawaan tertentu yang berkaitan dengan jenis JSON yang sudah ada, agar Anda dapat menulis kode yang lebih mudah dikelola.

Praktik terbaik untuk struktur data

Menghindari data bertingkat

Karena Firebase Realtime Database memungkinkan data bertingkat hingga kedalaman 32 tingkat, Anda mungkin akan berpikir bahwa pasti inilah struktur defaultnya. Namun, saat Anda mengambil data di sebuah lokasi dalam database Anda, Anda juga mengambil semua node turunannya. Selain itu, ketika Anda memberikan akses baca atau tulis kepada seseorang pada sebuah node di database Anda, Anda juga memberinya akses ke semua data di dalam node tersebut. Oleh karena itu, dalam praktiknya, lebih baik buat struktur data Anda serata mungkin.

Untuk memberi gambaran mengapa data yang bertingkat itu buruk, perhatikan struktur multi-tingkat berikut:

{
  // This is a poorly nested data architecture, because iterating the children
  // of the "chats" node to get a list of conversation titles requires
  // potentially downloading hundreds of megabytes of messages
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "messages": {
        "m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
        "m2": { ... },
        // a very long list of messages
      }
    },
    "two": { ... }
  }
}

Dengan desain bertingkat ini, iterasi data bisa bermasalah. Misalnya, untuk menampilkan daftar judul percakapan chat, seluruh hierarki chats harus didownload ke klien, termasuk semua anggota dan pesannya.

Meratakan struktur data

Jika data tersebut dibagi menjadi lokasi yang terpisah, disebut juga dengan denormalisasi, data tersebut dapat didownload secara efisien dalam panggilan terpisah, sesuai dengan kebutuhan. Perhatikan struktur yang diratakan ini:

{
  // Chats contains only meta info about each conversation
  // stored under the chats's unique ID
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    },
    "two": { ... },
    "three": { ... }
  },

  // Conversation members are easily accessible
  // and stored by chat conversation ID
  "members": {
    // we'll talk about indices like this below
    "one": {
      "ghopper": true,
      "alovelace": true,
      "eclarke": true
    },
    "two": { ... },
    "three": { ... }
  },

  // Messages are separate from data we may want to iterate quickly
  // but still easily paginated and queried, and organized by chat
  // conversation ID
  "messages": {
    "one": {
      "m1": {
        "name": "eclarke",
        "message": "The relay seems to be malfunctioning.",
        "timestamp": 1459361875337
      },
      "m2": { ... },
      "m3": { ... }
    },
    "two": { ... },
    "three": { ... }
  }
}

Iterasi melalui daftar ruang sekarang dapat dilakukan cukup dengan mendownload beberapa byte dari setiap percakapan. Dengan begitu, mengambil metadata untuk pendataan atau menampilkan ruang di UI bisa dilakukan dengan cepat. Pesan dapat diambil secara terpisah dan ditampilkan saat pesan itu tiba, sehingga UI akan tetap cepat dan responsif.

Membuat data yang berkembang

Ketika membuat aplikasi, mendownload subkumpulan dari daftar seringkali merupakan keputusan yang lebih baik. Praktik ini biasa dilakukan, terutama jika daftar tersebut memuat ribuan catatan. Jika hubungan ini bersifat statis dan satu arah, Anda cukup menempatkan objek turunan di bawah induk.

Terkadang, hubungan ini bersifat lebih dinamis, atau denormalisasi mungkin perlu dilakukan pada data ini. Biasanya, denormalisasi data dapat dilakukan dengan menggunakan kueri untuk mengambil subkumpulan data, seperti yang dibahas dalam bagian Mengambil Data.

Tetapi ini pun mungkin tidak cukup. Bayangkan, misalnya, hubungan dua arah antara pengguna dan grup. Pengguna dapat mengikuti sebuah grup, sementara grup terdiri dari daftar pengguna. Keadaan menjadi rumit saat Anda harus menentukan grup mana saja yang diikuti pengguna.

Yang diperlukan adalah cara yang unik untuk mendata grup pengguna dan hanya mengambil data untuk grup tersebut. Indeks grup dapat sangat membantu di sini:

// An index to track Ada's memberships
{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      // Index Ada's groups in her profile
      "groups": {
         // the value here doesn't matter, just that the key exists
         "techpioneers": true,
         "womentechmakers": true
      }
    },
    ...
  },
  "groups": {
    "techpioneers": {
      "name": "Historical Tech Pioneers",
      "members": {
        "alovelace": true,
        "ghopper": true,
        "eclarke": true
      }
    },
    ...
  }
}

Anda mungkin menyadari bahwa tindakan ini akan menduplikat beberapa data dengan cara menyimpan hubungan di catatan Ada maupun di grup. Sekarang, alovelace diindeks dalam grup dan techpioneers tercantum pada profil Ada. Jadi, untuk menghapus Ada dari grup, update harus dilakukan di dua tempat.

Ini adalah redundansi yang diperlukan untuk hubungan dua arah. Dengan begitu, Anda dapat mengambil keanggotaan Ada dengan cepat dan efisien, bahkan ketika daftar pengguna atau grup bertambah menjadi jutaan, atau ketika aturan keamanan Realtime Database menghalangi akses ke beberapa catatan tersebut.

Pendekatan yang membalikkan data dengan mencantumkan ID sebagai kunci dan menetapkan nilainya ke BENAR ini membuat proses pemeriksaan kunci menjadi semudah membaca /users/$uid/groups/$group_id dan memeriksa apakah nilainya null. Indeks ini lebih cepat dan jauh lebih efisien daripada proses kueri atau memindai data.

Langkah Berikutnya

Kirim masukan tentang...

Firebase Realtime Database
Butuh bantuan? Kunjungi halaman dukungan kami.