Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

Structuration des données avec Firebase Realtime Database pour C++

Structurer les données

Ce guide couvre certains des concepts clés de l'architecture des données et les meilleures pratiques pour structurer les données JSON dans votre base de données en temps réel Firebase.

Construire une base de données correctement structurée nécessite un peu de prévoyance. Plus important encore, vous devez planifier la manière dont les données seront enregistrées et récupérées ultérieurement pour rendre ce processus aussi simple que possible.

Comment les données sont structurées : c'est un arbre JSON

Toutes les données de la base de données Firebase Realtime sont stockées en tant qu'objets JSON. Vous pouvez considérer la base de données comme une arborescence JSON hébergée dans le cloud. Contrairement à une base de données SQL, il n'y a pas de tables ou d'enregistrements. Lorsque vous ajoutez des données à l'arborescence JSON, elles deviennent un nœud dans la structure JSON existante avec une clé associée. Vous pouvez fournir vos propres clés, telles que les ID utilisateur ou les noms sémantiques, ou ils peuvent être fournis pour vous en utilisant le Push() méthode.

Si vous créez vos propres clés, ils doivent être UTF-8 codé, peut être un maximum de 768 octets, et ne peuvent pas contenir . , $ , # , [ , ] , / Ou des caractères de contrôle ASCII 0-31 ou 127. Vous ne pouvez pas utiliser des caractères de contrôle ASCII dans les valeurs elles - mêmes, que ce soit.

Par exemple, considérons une application de chat qui permet aux utilisateurs de stocker un profil de base et une liste de contacts. Un profil utilisateur typique est situé à un chemin, comme /users/$uid . L'utilisateur alovelace pourrait avoir une entrée de base de données qui ressemble à ceci:

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

Bien que la base de données utilise une arborescence JSON, les données stockées dans la base de données peuvent être représentées comme certains types natifs qui correspondent aux types JSON disponibles pour vous aider à écrire un code plus facile à gérer.

Meilleures pratiques pour la structure des données

Éviter l'imbrication des données

Étant donné que la base de données en temps réel Firebase permet d'imbriquer des données jusqu'à 32 niveaux de profondeur, vous pourriez être tenté de penser que cela devrait être la structure par défaut. Cependant, lorsque vous récupérez des données à un emplacement de votre base de données, vous récupérez également tous ses nœuds enfants. De plus, lorsque vous accordez à quelqu'un un accès en lecture ou en écriture sur un nœud de votre base de données, vous lui accordez également l'accès à toutes les données sous ce nœud. Par conséquent, dans la pratique, il est préférable de garder votre structure de données aussi plate que possible.

Pour obtenir un exemple des raisons pour lesquelles les données imbriquées sont incorrectes, considérez la structure à emboîtement multiple suivante :

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

Avec cette conception imbriquée, l'itération à travers les données devient problématique. Par exemple, la liste des titres de conversations chat nécessite l'ensemble des chats arbre, y compris tous les membres et les messages, à télécharger au client.

Aplatir les structures de données

Si les données sont plutôt divisées en chemins séparés, également appelés dénormalisation, elles peuvent être téléchargées efficacement dans des appels séparés, selon les besoins. Considérez cette structure aplatie :

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

Il est désormais possible de parcourir la liste des salles en ne téléchargeant que quelques octets par conversation, en récupérant rapidement les métadonnées pour répertorier ou afficher les salles dans une interface utilisateur. Les messages peuvent être récupérés séparément et affichés au fur et à mesure de leur arrivée, ce qui permet à l'interface utilisateur de rester réactive et rapide.

Créez des données qui évoluent

Lors de la création d'applications, il est souvent préférable de télécharger un sous-ensemble d'une liste. Ceci est particulièrement courant si la liste contient des milliers d'enregistrements. Lorsque cette relation est statique et unidirectionnelle, vous pouvez simplement imbriquer les objets enfants sous le parent.

Parfois, cette relation est plus dynamique, ou il peut être nécessaire de dénormaliser ces données. Plusieurs fois , vous pouvez dénormaliser les données à l'aide d' une requête pour récupérer un sous - ensemble des données, comme indiqué dans Récupérer des données .

Mais même cela peut être insuffisant. Considérons, par exemple, une relation bidirectionnelle entre les utilisateurs et les groupes. Les utilisateurs peuvent appartenir à un groupe et les groupes comprennent une liste d'utilisateurs. Quand vient le temps de décider à quels groupes appartient un utilisateur, les choses se compliquent.

Ce qu'il faut, c'est une manière élégante de répertorier les groupes auxquels un utilisateur appartient et de récupérer uniquement les données pour ces groupes. Un index des groupes peut aider beaucoup ici:

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

Vous remarquerez peut-être que cela duplique certaines données en stockant la relation à la fois sous l'enregistrement d'Ada et sous le groupe. Maintenant alovelace est indexé sous un autre groupe, et techpioneers est listé dans le profil de Ada. Donc, pour supprimer Ada du groupe, il doit être mis à jour à deux endroits.

Il s'agit d'une redondance nécessaire pour les relations bidirectionnelles. Il vous permet de récupérer rapidement et efficacement les adhésions d'Ada, même lorsque la liste d'utilisateurs ou de groupes atteint des millions ou lorsque les règles de sécurité de la base de données en temps réel empêchent l'accès à certains des enregistrements.

Cette approche, en inversant les données en énumérant les ID en tant que clés et définir la valeur true, permet de vérifier une clé aussi simple que la lecture /users/$uid/groups/$group_id et vérifier si elle est null . L'index est plus rapide et bien plus efficace que l'interrogation ou l'analyse des données.

Prochaines étapes