59 votes

Comment obtenir un nombre de documents dans une collection avec Cloud Firestore

Dans Firestore, comment puis-je obtenir le nombre total de documents dans une collection ?

Par exemple, si j'ai

Je veux interroger combien de personnes j'ai et obtenir 2.

Je pourrais faire une requête sur / personnes et ensuite obtenir la longueur des résultats retournés, mais cela semble un gaspillage, surtout parce que je vais le faire sur de plus grands jeux de données.

50voto

Dan McGrath Points 9839

Actuellement vous avez 3 options:

Option 1: côté Client

C'est fondamentalement l'approche que vous avez mentionné. Sélectionnez tous de collecte et de compter sur le côté client. Cela fonctionne assez bien pour les petits ensembles de données, mais de toute évidence ne fonctionne pas si le jeu de données est plus grande.

Option 2: Écriture d'un temps meilleur effort

Avec cette approche, vous pouvez utiliser le Cloud Fonctions pour mettre à jour un compteur pour chaque ajout et la suppression de la collection.

Cela fonctionne bien pour tout jeu de données de taille, tant que les ajouts/suppressions ne se produisent qu'au taux inférieur ou égal à 1 par seconde. Cela vous donne un seul document à lire pour vous donner la presque actuel comte immédiatement.

Si besoin besoin de dépasser 1 par seconde, vous avez besoin pour mettre en œuvre distribué des compteurs par notre documentation.

Option 3: Écriture exacte

Plutôt que d'utiliser le Cloud Fonctions, dans votre client que vous pouvez mettre à jour le compteur en même temps que vous ajoutez ou supprimez un document. Cela signifie que le compteur va également être à jour, mais vous devez assurez-vous d'inclure cette logique où vous le ajouter ou supprimer des documents.

Comme dans l'option 2, vous aurez besoin de mettre en œuvre des distribué des compteurs si vous voulez dépasser par seconde

9voto

Ben Cochrane Points 2026

Les agrégations sont la voie à suivre (firebase fonctions ressemble à la méthode recommandée de mise à jour de ces agrégations côté client expose les informations à l'utilisateur, vous ne voulez pas exposé) https://firebase.google.com/docs/firestore/solutions/aggregation

Une autre façon (NON recommandé), qui n'est pas bon pour les grandes listes et implique le téléchargement de l'ensemble de la liste: res.la taille comme dans cet exemple:

db.collection('products').get().then(res => console.log(res.size))

4voto

Johan Chouquet Points 21

Si vous utilisez AngulareFire2, vous pouvez le faire (en supposant `` qu'il soit injecté dans votre constructeur) :

Voici, est un tableau de tous les éléments dans . Vous n'avez pas besoin de métadonnées de sorte que vous pouvez utiliser la `` méthode directement.

2voto

Ferran Verdés Points 136

Attention comptage du nombre de documents pour les grandes collections avec une fonction cloud. C'est un peu complexe avec firestore base de données si vous voulez avoir un précalculées compteur pour chaque collection.

Ce Code ne fonctionne pas dans ce cas:

export const customerCounterListener = 
    functions.firestore.document('customers/{customerId}')
    .onWrite((change, context) => {

    // on create
    if (!change.before.exists && change.after.exists) {
        return firestore
                 .collection('metadatas')
                 .doc('customers')
                 .get()
                 .then(docSnap =>
                     docSnap.ref.set({
                         count: docSnap.data().count + 1
                     }))
    // on delete
    } else if (change.before.exists && !change.after.exists) {
        return firestore
                 .collection('metadatas')
                 .doc('customers')
                 .get()
                 .then(docSnap =>
                     docSnap.ref.set({
                         count: docSnap.data().count - 1
                     }))
    }

    return null;
});

La raison en est que tous les nuages firestore détente doit être idempotent, comme firestore documentation dire: https://firebase.google.com/docs/functions/firestore-events#limitations_and_guarantees

Solution

Ainsi, afin d'éviter que plusieurs exécutions de votre code, vous avez besoin pour gérer les événements et les transactions. C'est ma façon particulière de traiter de gros de la collection de compteurs:

const executeOnce = (change, context, task) => {
    const eventRef = firestore.collection('events').doc(context.eventId);

    return firestore.runTransaction(t =>
        t
         .get(eventRef)
         .then(docSnap => (docSnap.exists ? null : task(t)))
         .then(() => t.set(eventRef, { processed: true }))
    );
};

const documentCounter = collectionName => (change, context) =>
    executeOnce(change, context, t => {
        // on create
        if (!change.before.exists && change.after.exists) {
            return t
                    .get(firestore.collection('metadatas')
                    .doc(collectionName))
                    .then(docSnap =>
                        t.set(docSnap.ref, {
                            count: ((docSnap.data() && docSnap.data().count) || 0) + 1
                        }));
        // on delete
        } else if (change.before.exists && !change.after.exists) {
            return t
                     .get(firestore.collection('metadatas')
                     .doc(collectionName))
                     .then(docSnap =>
                        t.set(docSnap.ref, {
                            count: docSnap.data().count - 1
                        }));
        }

        return null;
    });

Les cas d'utilisation ici:

/**
 * Count documents in articles collection.
 */
exports.articlesCounter = functions.firestore
    .document('articles/{id}')
    .onWrite(documentCounter('articles'));

/**
 * Count documents in customers collection.
 */
exports.customersCounter = functions.firestore
    .document('customers/{id}')
    .onWrite(documentCounter('customers'));

Comme vous pouvez le voir, la clé pour empêcher l'exécution de plusieurs est la propriété appelée id de l'événement dans le contexte de l'objet. Si la fonction a été traitée de nombreuses fois pour le même événement, l'id d'événement sera le même dans tous les cas. Malheureusement, vous devez avoir des "événements" de la collection dans votre base de données.

0voto

Saint Play Points 683

Suite à La réponse Dan: Vous pouvez avoir un compteur séparé dans votre base de données et utiliser les fonctions Cloud pour le maintenir. (Ecrire-temps best-effort)

Ce code vous montre l'exemple complet de la façon de le faire: https://gist.github.com/saintplay/3f965e0aea933a1129cc2c9a823e74d7

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