قم ببناء قاعدة البيانات الخاصة بك

يغطي هذا الدليل بعض المفاهيم الأساسية في هندسة البيانات وأفضل الممارسات لهيكلة بيانات JSON في قاعدة بيانات Firebase Realtime.

يتطلب بناء قاعدة بيانات منظمة بشكل صحيح قدرًا كبيرًا من التفكير. الأهم من ذلك ، أنك تحتاج إلى التخطيط لكيفية حفظ البيانات واستردادها لاحقًا لجعل هذه العملية سهلة قدر الإمكان.

كيف يتم تنظيم البيانات: إنها شجرة JSON

يتم تخزين جميع بيانات قاعدة بيانات Firebase Realtime ككائنات JSON. يمكنك التفكير في قاعدة البيانات على أنها شجرة JSON مستضافة على السحابة. على عكس قاعدة بيانات SQL ، لا توجد جداول أو سجلات. عند إضافة بيانات إلى شجرة JSON ، فإنها تصبح عقدة في بنية JSON الحالية بمفتاح مرتبط بها. يمكن أن توفر مفاتيح الخاصة بك، مثل هوية المستخدم أو أسماء الدلالي، أو أنها يمكن أن توفر لك باستخدام push() .

إذا قمت بإنشاء مفاتيح الخاصة بك، يجب أن تكون UTF-8 المشفرة، يمكن أن يكون بحد أقصى 768 بايت، ولا يمكن احتواء . ، $ ، # ، [ ، ] ، / أو أحرف التحكم ASCII 0-31 أو 127. لا يمكنك استخدام أحرف التحكم ASCII في القيم نفسها، إما.

على سبيل المثال ، ضع في اعتبارك تطبيق دردشة يتيح للمستخدمين تخزين ملف تعريف أساسي وقائمة جهات اتصال. يقع ملف تعريف مستخدم نموذجي في مسار مثل /users/$uid . المستخدم alovelace قد يكون إدخال قاعدة بيانات ويبدو أن شيئا من هذا القبيل:

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

على الرغم من أن قاعدة البيانات تستخدم شجرة JSON ، يمكن تمثيل البيانات المخزنة في قاعدة البيانات على أنها أنواع أصلية معينة تتوافق مع أنواع JSON المتاحة لمساعدتك في كتابة تعليمات برمجية أكثر قابلية للصيانة.

أفضل الممارسات لهيكل البيانات

تجنب البيانات المتداخلة

نظرًا لأن قاعدة بيانات Firebase Realtime تسمح بتداخل البيانات حتى عمق 32 مستوى ، فقد تميل إلى الاعتقاد بأن هذا يجب أن يكون الهيكل الافتراضي. ومع ذلك ، عندما تقوم بإحضار البيانات من موقع في قاعدة البيانات الخاصة بك ، فإنك تقوم أيضًا باسترداد جميع العقد الفرعية الخاصة بها. بالإضافة إلى ذلك ، عندما تمنح شخصًا حق الوصول للقراءة أو الكتابة في عقدة في قاعدة البيانات الخاصة بك ، فإنك تمنحه أيضًا حق الوصول إلى جميع البيانات الموجودة ضمن تلك العقدة. لذلك ، من الناحية العملية ، من الأفضل الحفاظ على بنية بياناتك مسطحة قدر الإمكان.

للحصول على مثال حول سبب سوء البيانات المتداخلة ، ضع في اعتبارك البنية متعددة المتداخلة التالية:

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

مع هذا التصميم المتداخل ، يصبح التكرار خلال البيانات مشكلة. على سبيل المثال، قائمة عناوين محادثات الدردشة يتطلب كامل chats شجرة، بما في ذلك جميع أعضاء والرسائل، ليتم تحميلها إلى العميل.

تسطيح هياكل البيانات

إذا تم تقسيم البيانات بدلاً من ذلك إلى مسارات منفصلة ، وتسمى أيضًا عدم التطابق ، فيمكن تنزيلها بكفاءة في مكالمات منفصلة ، حسب الحاجة. ضع في اعتبارك هذا الهيكل المسطح:

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

أصبح من الممكن الآن تكرار قائمة الغرف عن طريق تنزيل عدد قليل من وحدات البايت لكل محادثة ، وسرعة جلب البيانات الوصفية لإدراج أو عرض الغرف في واجهة المستخدم. يمكن جلب الرسائل بشكل منفصل وعرضها عند وصولها ، مما يسمح لواجهة المستخدم بالبقاء متجاوبة وسريعة.

قم بإنشاء بيانات قابلة للتوسيع

عند إنشاء التطبيقات ، غالبًا ما يكون من الأفضل تنزيل مجموعة فرعية من القائمة. هذا شائع بشكل خاص إذا كانت القائمة تحتوي على آلاف السجلات. عندما تكون هذه العلاقة ثابتة وذات اتجاه واحد ، يمكنك ببساطة تضمين الكائنات الفرعية تحت العنصر الرئيسي.

في بعض الأحيان ، تكون هذه العلاقة أكثر ديناميكية ، أو قد يكون من الضروري إلغاء تسوية هذه البيانات. وفي كثير من الأحيان يمكنك إلغاء تطبيع البيانات باستخدام استعلام لاسترداد مجموعة فرعية من البيانات، كما نوقش في استرداد البيانات .

لكن حتى هذا قد يكون غير كاف. ضع في اعتبارك ، على سبيل المثال ، علاقة ثنائية الاتجاه بين المستخدمين والمجموعات. يمكن للمستخدمين الانتماء إلى مجموعة ، وتشكل المجموعات قائمة بالمستخدمين. عندما يحين وقت تحديد المجموعات التي ينتمي إليها المستخدم ، تصبح الأمور معقدة.

ما هو مطلوب هو طريقة أنيقة لسرد المجموعات التي ينتمي إليها المستخدم وجلب البيانات فقط لتلك المجموعات. مؤشر الجماعات يمكن أن تساعد كثيرا هنا:

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

قد تلاحظ أن هذا يكرر بعض البيانات عن طريق تخزين العلاقة تحت كل من سجل Ada وتحت المجموعة. الآن alovelace تتم فهرسة تحت مجموعة، و techpioneers يتم سرد في ملفه آدا. لذا لحذف Ada من المجموعة ، يجب تحديثها في مكانين.

هذا تكرار ضروري للعلاقات ثنائية الاتجاه. يسمح لك بجلب عضويات Ada بسرعة وكفاءة ، حتى عندما تتسع قائمة المستخدمين أو المجموعات إلى الملايين أو عندما تمنع قواعد أمان Realtime Database الوصول إلى بعض السجلات.

هذا النهج، عكس البيانات من خلال سرد معرفات كمفاتيح وتعيين القيمة إلى true، يجعل التحقق من وجود مفتاح بسيطة مثل قراءة /users/$uid/groups/$group_id وفحص إذا كان null . الفهرس أسرع وأكثر كفاءة بكثير من الاستعلام عن البيانات أو مسحها ضوئيًا.

الخطوات التالية