Données structurantes
Sur cette page
La base de données Firebase est une base de données NoSQL qui stocke ses données sous la forme d’objets JSON hiérarchiques. Il n’y a pas de tables ou d’enregistrements de quelque forme que ce soit qu’une base de données SQL aurait normalement, juste des nœuds qui constituent une structure clé-valeur.
** Normalisation des données **
Afin d’avoir une structure de base de données correctement conçue, les exigences en matière de données doivent être soigneusement définies et anticipées. La structure dans ce cas doit être normalisée; plus l’arborescence JSON est plate, plus l’accès aux données est rapide.
À faire et à ne pas faire
La mauvaise direction
Considérez la structure suivante
{
"users": {
// Uniquely generated IDs for children is common practice,
// it's actually really useful for automating child creation.
// Auto-incrementing an integer for a key can be problematic when a child is removed.
"-KH3Cx0KFvSQELIYZezv": {
"name": "Jon Snow",
"aboutMe": "I know nothing...",
"posts": {
"post1": {
"body": "Different roads sometimes leads to the same castle",
"isHidden": false
},
"post2": { ... },
// Possibly more posts
}
},
"-KH3Dx2KFdSLErIYZcgk": { ... }, // Another user
// A lot more users here
}
}
C’est un excellent exemple de ce qu’il NE PAS faire. Les structures multi-imbriquées telles que celle ci-dessus peuvent être très problématiques et peuvent entraîner un énorme recul des performances.
Firebase accède à un nœud en téléchargeant toutes les données des enfants, puis en itérant sur tous les nœuds de même niveau (tous les enfants des parents). Maintenant, imaginez une base de données avec plusieurs utilisateurs, chacun ayant des centaines (voire des milliers) de messages. Accéder à un post dans ce cas pourrait potentiellement charger des centaines de mégaoctets de données inutilisées. Dans une application plus compliquée, l’imbrication pourrait être plus profonde que 4 couches, ce qui entraînerait davantage de téléchargements et d’itérations inutiles.
Le droit chemin
Aplatir la même structure ressemblerait à ceci
{
// "users" should not contain any of the posts' data
"users": {
"-KH3Cx0KFvSQELIYZezv": {
"name": "Jon Snow",
"aboutMe": "I know nothing..."
},
"-KH3Dx2KFdSLErIYZcgk": { ... },
// More users
},
// Posts can be accessed provided a user key
"posts": {
"-KH3Cx0KFvSQELIYZezv": { // Jon Snow's posts
"post1": {
"body": "Different roads sometimes leads to the same castle",
"isHidden": false
},
"post2": { ... },
// Possibly more posts
},
"-KH3Dx2KFdSLErIYZcgk": { ... },
// other users' posts
}
}
Cela permet d’économiser une énorme quantité de temps système en itérant sur moins de nœuds pour accéder à un objet cible. Tous les utilisateurs qui n’ont pas de messages n’existeraient pas dans la branche posts, et donc itérer sur ces utilisateurs dans le mauvais chemin ci-dessus est complètement inutile.
Relations à double sens
Ce qui suit est un exemple d’une base de données d’université simple et minimale qui utilise des relations bidirectionnelles
{
"students": {
"-SL3Cs0KFvDMQLIYZEzv": {
"name": "Godric Gryffindor",
"id": "900130309",
"courses": {
"potions": true,
"charms": true,
"transfiguration": true,
}
},
"-SL3ws2KvZQLTYMqzSas": {
"name": "Salazar Slytherin",
"id": "900132319",
"courses": {
"potions": true,
"herbs": true,
"muggleStudies": true,
}
},
"-SL3ns2OtARSTUMywqWt": { ... },
// More students here
},
"courses": {
"potions": {
"code": "CHEM305",
"enrolledStudents": {
"-SL3Cs0KFvDMQLIYZEzv": true, // Godric Gryffindor
"-SL3ws2KvZQLTYMqzSas": true, // Salazar Slytherin
// More students
}
},
"muggleStuddies": {
"code": "SOC215",
"enrolledStudents": {
"-SL3ws2KvZQLTYMqzSas": true, // Salazar Slytherin
"-SL3ns2OtARSTUMywqWt": true, // Some other student
// More students
}
},
// More courses
}
}
Notez que chaque étudiant a une liste de cours et chaque cours a une liste d’étudiants inscrits.
La redondance n’est pas toujours une mauvaise approche. Il est vrai que cela coûte de l’espace de stockage et doit gérer la mise à jour de plusieurs entrées lors de la suppression ou de la modification d’un nœud dupliqué ; cependant, dans certains scénarios où les données ne sont pas souvent mises à jour, le fait d’avoir des relations bidirectionnelles peut faciliter considérablement le processus de récupération/d’écriture.
Dans la plupart des scénarios où une requête de type SQL semble nécessaire, inverser les données et créer des relations bidirectionnelles est généralement la solution.
Considérez une application utilisant la base de données ci-dessus qui nécessite la capacité de :
- Énumérez les cours suivis par un certain étudiant et…
- Lister tous les étudiants d’un certain cours
Si la structure de la base de données avait été unidirectionnelle, il serait incroyablement plus lent d’analyser ou d’interroger l’une des deux exigences ci-dessus. Dans certains scénarios, la redondance rend les opérations fréquentes plus rapides et beaucoup plus efficaces, ce qui, à long terme, rend le coût des duplications négligeable.