Veritabanınızı Yapılandırma

Bu kılavuzda, veri mimarisiyle ilgili bazı temel kavramlar ve Firebase Realtime Database'inizde JSON verilerini yapılandırmayla ilgili en iyi uygulamalar açıklanmaktadır.

Düzgün yapılandırılmış bir veritabanı oluşturmak için ayrıntılı bir şekilde düşünmek gerekir. En önemlisi, süreci mümkün olduğunca kolaylaştırmak için verilerin nasıl kaydedileceğini ve daha sonra alınacağını planlamanız gerekir.

Veriler nasıl yapılandırılır? Bir JSON ağacıdır

Tüm Firebase Realtime Database verileri JSON nesneleri olarak saklanır. Veritabanını bulutta barındırılan bir JSON ağacı gibi düşünebilirsiniz. SQL veritabanının aksine tablo veya kayıt yoktur. JSON ağacına veri eklediğinizde bu veri, mevcut JSON yapısında ilişkili bir anahtarla birlikte bir düğüm haline gelir. Kullanıcı kimlikleri veya anlamsal adlar gibi kendi anahtarlarınızı sağlayabilirsiniz ya da push() yöntemi kullanılarak sizin için sağlanabilirler.

Kendi anahtarlarınızı oluşturursanız anahtarlarınız UTF-8 olarak kodlanmış olmalı, en fazla 768 bayt büyüklüğünde olabilir ve ., $, #, [, ], / veya 0-31 ya da 127 ASCII kontrol karakterlerini içeremez. Değerlerin kendilerinde ASCII kontrol karakterleri de kullanamazsınız.

Örneğin, kullanıcıların temel bir profili ve kişi listesini saklamasına olanak tanıyan bir sohbet uygulaması düşünün. Tipik bir kullanıcı profili, /users/$uid gibi bir yolda bulunur. alovelace kullanıcısının veritabanı girişi aşağıdaki gibi görünebilir:

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

Veritabanı bir JSON ağacı kullanmasına rağmen veritabanında depolanan veriler, daha sürdürülebilir kodlar yazmanıza yardımcı olmak için mevcut JSON türlerine karşılık gelen belirli yerel türler olarak temsil edilebilir.

Veri yapısıyla ilgili en iyi uygulamalar

Verileri iç içe yerleştirmekten kaçınma

Firebase Realtime Database, verilerin 32 seviyeye kadar derinlikte iç içe yerleştirilmesine olanak tanıdığından bunun varsayılan yapı olması gerektiğini düşünmek isteyebilirsiniz. Ancak, veritabanınızdaki bir konumda veri getirdiğinizde, veritabanının tüm alt düğümlerini de alırsınız. Buna ek olarak, bir kişiye veritabanınızdaki bir düğümde okuma veya yazma erişimi verdiğinizde, ona o düğüm altındaki tüm verilere erişim de vermiş olursunuz. Bu nedenle, uygulamada veri yapınızı mümkün olduğunca düz tutmak en iyisidir.

İç içe yerleştirilmiş verilerin neden kötü olduğuna dair bir örnek için aşağıdaki çarpılmış iç içe yapıyı göz önünde bulundurun:

{
  // 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": { ... }
  }
}

İç içe yerleştirilmiş bu tasarımla, verileri yinelemek sorun yaratır. Örneğin, sohbet görüşmelerinin başlıklarının listelenmesi, tüm üyeler ve iletiler de dahil olmak üzere chats ağacının tamamının istemciye indirilmesini gerektirir.

Veri yapılarını birleştir

Veriler bunun yerine denormalizasyon olarak da adlandırılan ayrı yollara bölünürse ihtiyaç duyulduğunda ayrı çağrılarda verimli bir şekilde indirilebilir. Şu birleştirilmiş yapıyı bir düşünün:

{
  // 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": { ... }
  }
}

Artık her sohbet için yalnızca birkaç bayt indirerek, kullanıcı arayüzünde odaları listeleme veya görüntülemeyle ilgili meta verileri hızlıca alarak odalar listesinde iterasyon yapmak mümkündür. Mesajlar ayrı olarak getirilebilir ve geldikçe görüntülenebilir. Böylece kullanıcı arayüzü duyarlı ve hızlı kalır.

Ölçeklenen veriler oluşturun

Uygulama oluştururken bir listenin bir alt kümesini indirmek genellikle daha iyidir. Bu durum özellikle listede binlerce kayıt varsa görülür. Bu ilişki statik ve tek yönlü olduğunda, alt nesneleri üst öğenin altına iç içe yerleştirebilirsiniz.

Bazen bu ilişki daha dinamik olur veya bu verileri normal dışı bırakmak gerekebilir. Çoğu zaman, Veri Alma bölümünde açıklandığı gibi, verilerin alt kümesini almak için bir sorgu kullanarak verileri normal dışı bırakabilirsiniz.

Ancak bu bile yeterli olmayabilir. Örneğin, kullanıcılar ile gruplar arasında iki yönlü bir ilişki düşünün. Kullanıcılar bir gruba ait olabilir ve gruplar, kullanıcıların bir listesini oluşturur. Bir kullanıcının hangi gruplara ait olduğuna karar verme zamanı geldiğinde, işler karmaşık hale gelir.

Gerekli olan, kullanıcının ait olduğu grupları listelemenin ve yalnızca bu grupların verilerini getirmenin zarif bir yoludur. Grup dizini burada çok yardımcı olabilir:

// 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
      }
    },
    ...
  }
}

Bu işlemin, ilişkiyi hem Ada'nın kaydı hem de grubun altında depolayarak bazı verilerin yinelendiğini fark edebilirsiniz. alovelace artık bir grup altında dizine eklenmiş ve techpioneers, Ada'nın profilinde listeleniyor. Ada'nın gruptan silinmesi için iki yerde güncellenmesi gerekiyor.

Bu, iki taraflı ilişkiler için gerekli bir yedektir. Kullanıcı veya grup listesi milyonlara ulaştığında ya da Realtime Database güvenlik kuralları bazı kayıtlara erişimi engellediğinde bile Ada'nın üyeliklerini hızlı ve etkili bir şekilde getirmenizi sağlar.

Kimlikleri anahtar olarak listeleyip değeri "doğru" olarak ayarlayarak verileri tersine çeviren bu yaklaşım, anahtarın kontrol edilmesini /users/$uid/groups/$group_id okumak ve null olup olmadığını kontrol etmek kadar basit hale getirir. Dizin, verileri sorgulamak veya taramaktan daha hızlıdır ve oldukça verimlidir.

Sonraki adımlar