144 votes

Dans Firebase, y a-t-il un moyen d'obtenir le nombre d'enfants d'un noeud sans charger toutes les données du noeud ?

Vous pouvez obtenir le nombre d'enfants via

firebase_node.once('value', function(snapshot) { alert('Count: ' + snapshot.numChildren()); });

Mais je crois que cela récupère le sous-arbre entier de ce nœud depuis le serveur. Pour les grandes listes, cela semble gourmand en mémoire vive et en latence. Existe-t-il un moyen d'obtenir le nombre (et/ou une liste de noms d'enfants) sans aller chercher la totalité de l'arbre ?

108voto

Andrew Lee Points 3704

L'extrait de code que vous avez donné charge effectivement l'ensemble des données et les compte ensuite côté client, ce qui peut être très lent pour de grandes quantités de données.

Firebase ne dispose pas actuellement d'un moyen de compter les enfants sans charger les données, mais nous prévoyons de l'ajouter.

Pour l'instant, une solution serait de maintenir un compteur du nombre d'enfants et de le mettre à jour chaque fois que vous ajoutez un nouvel enfant. Vous pourriez utiliser une transaction pour compter les éléments, comme dans ce code de suivi des upvodes :

var upvotesRef = new Firebase('https://docs-examples.firebaseio.com/android/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes');
upvotesRef.transaction(function (current_value) {
  return (current_value || 0) + 1;
});

Pour plus d'informations, voir https://www.firebase.com/docs/transactions.html

UPDATE : Firebase a récemment publié Cloud Functions. Avec Cloud Functions, vous n'avez pas besoin de créer votre propre serveur. Vous pouvez simplement écrire des fonctions JavaScript et les télécharger sur Firebase. Firebase se chargera de déclencher les fonctions dès qu'un événement se produit.

Si vous voulez compter les upvotes par exemple, vous devez créer une structure similaire à celle-ci :

{
  "posts" : {
    "-JRHTHaIs-jNPLXOQivY" : {
      "upvotes_count":5,
      "upvotes" : {
      "userX" : true,
      "userY" : true,
      "userZ" : true,
      ...
    }
    }
  }
}

Et ensuite écrire une fonction javascript pour augmenter le upvotes_count lorsqu'il y a une nouvelle écriture dans le upvotes nœud.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.countlikes = functions.database.ref('/posts/$postid/upvotes').onWrite(event => {
  return event.data.ref.parent.child('upvotes_count').set(event.data.numChildren());
});

Vous pouvez lire le Documentation de savoir comment Commencez avec les fonctions en nuage .

Par ailleurs, un autre exemple de comptage des messages est présenté ici : https://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js

Mise à jour de janvier 2018

Le site docs firebase ont changé, de sorte qu'au lieu de event nous avons maintenant change et context .

Dans l'exemple donné, une erreur est générée, car elle indique que event.data est indéfinie. Ce modèle semble mieux fonctionner :

exports.countPrescriptions = functions.database.ref(`/prescriptions`).onWrite((change, context) => {
    const data = change.after.val();
    const count = Object.keys(data).length;
    return change.after.ref.child('_count').set(count);
});

```

41voto

Alex Klibisz Points 827

Il est un peu tard pour répondre à cette question, car plusieurs autres personnes ont déjà répondu de manière satisfaisante, mais je vais vous expliquer comment je pourrais la mettre en œuvre.

Cela repose sur le fait que le API REST de Firebase offre un shallow=true paramètre.

Supposons que vous ayez un post et chacun d'eux peut avoir un certain nombre de comments :

{
 "posts": {
  "$postKey": {
   "comments": {
     ...  
   }
  }
 }
}

Il est évident que vous ne voulez pas récupérer tous les commentaires, mais seulement le nombre de commentaires.

En supposant que vous ayez la clé d'un poste, vous pouvez envoyer une commande GET demande à https://yourapp.firebaseio.com/posts/[the post key]/comments?shallow=true .

Ceci retournera un objet de paires clé-valeur, où chaque clé est la clé d'un commentaire et sa valeur est true :

{
 "comment1key": true,
 "comment2key": true,
 ...,
 "comment9999key": true
}

La taille de cette réponse est beaucoup plus petite que la demande de données équivalentes, et vous pouvez maintenant calculer le nombre de clés dans la réponse pour trouver votre valeur (par exemple, commentCount = Object.keys(result).length ).

Cela ne résout pas complètement votre problème, car vous calculez toujours le nombre de clés renvoyées et vous ne pouvez pas nécessairement vous abonner à la valeur lorsqu'elle change, mais cela réduit considérablement la taille des données renvoyées sans nécessiter de modification de votre schéma.

23voto

pperrin Points 1095

Enregistrez le compte au fur et à mesure - et utilisez la validation pour le faire respecter. J'ai bricolé ceci - pour garder un compte des votes uniques et des comptes qui reviennent sans cesse ! Mais cette fois, j'ai testé ma suggestion ! (malgré les erreurs de copier/coller !).

Le "truc" ici est d'utiliser le nœud priorité comme le décompte des voix...

Les données sont :

vote/$issueBeingVotedOn/user/$uniqueIdOfVoter = thisVotesCount, priority=thisVotesCount vote/$issueBeingVotedOn/count = 'user/'+$idOfLastVoter, priority=CountofLastVote

,"vote": {
  ".read" : true
  ,".write" : true
  ,"$issue" : {
    "user" : {
      "$user" : {
        ".validate" : "!data.exists() && 
             newData.val()==data.parent().parent().child('count').getPriority()+1 &&
             newData.val()==newData.GetPriority()" 

L'utilisateur ne peut voter qu'une seule fois && le compte doit être supérieur d'une unité au compte actuel && la valeur des données doit être identique à la priorité.

      }
    }
    ,"count" : {
      ".validate" : "data.parent().child(newData.val()).val()==newData.getPriority() &&
             newData.getPriority()==data.getPriority()+1 "
    }

count (dernier votant réellement) - le vote doit exister et son nombre doit être égal à newcount, && newcount (priorité) ne peut augmenter que de un.

  }
}

Tester le script pour ajouter 10 votes par différents utilisateurs (pour cet exemple, les identifiants sont truqués, il faut utiliser auth.uid en production). Compte à rebours par (i--) 10 pour voir la validation échouer.

<script src='https://cdn.firebase.com/v0/firebase.js'></script>
<script>
  window.fb = new Firebase('https:...vote/iss1/');
  window.fb.child('count').once('value', function (dss) {
    votes = dss.getPriority();
    for (var i=1;i<10;i++) vote(dss,i+votes);
  } );

function vote(dss,count)
{
  var user='user/zz' + count; // replace with auth.id or whatever
  window.fb.child(user).setWithPriority(count,count);
  window.fb.child('count').setWithPriority(user,count);
}
</script>

Le "risque" ici est qu'un vote soit émis, mais que le compte ne soit pas mis à jour (haking ou script). C'est pourquoi les votes ont une "priorité" unique - le script devrait vraiment commencer par s'assurer qu'il n'y a pas de vote avec une priorité plus élevée que le compte actuel, s'il y en a un, il devrait terminer cette transaction avant de faire la sienne - demandez à vos clients de faire le ménage pour vous :)

Le compte doit être initialisé avec une priorité avant de commencer - forge ne vous permet pas de le faire, donc un stub script est nécessaire (avant que la validation soit active !).

4voto

indvin Points 41

Écrire une fonction cloud pour et mettre à jour le nombre de nœuds.

// below function to get the given node count.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.userscount = functions.database.ref('/users/')
    .onWrite(event => {

      console.log('users number : ', event.data.numChildren());

      return event.data.ref.parent.child('count/users').set(event.data.numChildren());
    }); 

Référer : https://firebase.google.com/docs/functions/database-events

Root--| |-users ( ce noeud contient la liste de tous les utilisateurs) |
|-compteur |-userscount : (ce noeud est ajouté dynamiquement par la fonction cloud avec le nombre d'utilisateurs)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X