Подсчитайте с помощью облачных функций Firestore - PullRequest
0 голосов
/ 21 февраля 2019

Мне нравится считать количество документов во вложенной коллекции с облачными функциями пожарного депо.

Моя база данных выглядит так: groups / {groupId} / members / {memberId}

Мне нравится считать количество участников (memberId) для каждой группы.Это означает, что каждая группа может иметь различное количество членов, и они могут увеличивать или уменьшать гибкость.

Буду рад вашим идеям: -).

Ответы [ 2 ]

0 голосов
/ 30 июня 2019

Мне потребовалось некоторое время, чтобы заставить это работать, поэтому я решил поделиться им с другими:

'use strict';

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

exports.countDocumentsChange = functions.firestore.document('library/{categoryId}/documents/{documentId}').onWrite((change, context) => {

    const categoryId = context.params.categoryId;
    const categoryRef = db.collection('library').doc(categoryId)
    let FieldValue = require('firebase-admin').firestore.FieldValue;

    if (!change.before.exists) {

        // new document created : add one to count
        categoryRef.update({numberOfDocs: FieldValue.increment(1)});
        console.log("%s numberOfDocs incremented by 1", categoryId);

    } else if (change.before.exists && change.after.exists) {

        // updating existing document : Do nothing

    } else if (!change.after.exists) {

        // deleting document : subtract one from count
        categoryRef.update({numberOfDocs: FieldValue.increment(-1)});
        console.log("%s numberOfDocs decremented by 1", categoryId);

    }

    return 0;
});
0 голосов
/ 21 февраля 2019

Я думаю о двух возможных подходах.

1.Непосредственно посчитайте документ коллекции

Вы бы использовали size свойство QuerySnapshot как

admin.firestore().collection('groups/{groupId}/members/{memberId}')
    .get()
    .then(querySnapshot => {
        console.log(querySnapshot.size);
        //....
        return null;
    });

Основная проблема здесь - это стоимость , если подколлекция содержит много документов: при выполнении этого запроса с вас будет взиматься плата за одно чтение для каждого документа подпункта.коллекция.

2.Другой подход состоит в том, чтобы поддерживать некоторые счетчики для каждой подгруппы

. Вы бы написали две облачные функции на основе распределенных счетчиков , как представлено в этой базе данных Firebase.элемент документации: https://firebase.google.com/docs/firestore/solutions/counters. В следующем примере мы используем 3 осколка.

Во-первых, облачная функция увеличивает счетчик при добавлении нового документа в подгруппу subCollec:

//....
const num_shards = 3;
//....

exports.incrementSubCollecCounter = functions
  .firestore.document('groups/{groupId}/members/{memberId}')
  .onCreate((snap, context) => {

    const groupId = context.params.groupId;

    const shard_id = Math.floor(Math.random() * num_shards).toString();
    const shard_ref = admin
      .firestore()
      .collection('shards' + groupId)
      .doc(shard_id);

    if (!snap.data().counterIncremented) {
      return admin.firestore().runTransaction(t => {
        return t
          .get(shard_ref)
          .then(doc => {
            if (!doc.exists) {
              throw new Error(
                'Shard doc #' +
                  shard_id +
                  ' does not exist.'
              );
            } else {
              const new_count = doc.data().count + 1;
              return t.update(shard_ref, { count: new_count });
            }
          })
          .then(() => {
            return t.update(snap.ref, {
              counterIncremented: true    //This is important to have the Function idempotent, see https://cloud.google.com/functions/docs/bestpractices/tips#write_idempotent_functions
            });
          });
      });
    } else {
      console.log('counterIncremented NOT NULL');
      return null;
    }
  });

Тогда вторая облачная функция уменьшит счетчик при удалении документа из подгруппы subCollec:

exports.decrementSubCollecCounter = functions
  .firestore.document('groups/{groupId}/members/{memberId}')
  .onDelete((snap, context) => {

    const groupId = context.params.groupId;

    const shard_id = Math.floor(Math.random() * num_shards).toString();
    const shard_ref = admin
      .firestore()
      .collection('shards' + groupId)
      .doc(shard_id);

    return admin.firestore().runTransaction(t => {
      return t.get(shard_ref).then(doc => {
        if (!doc.exists) {
          throw new Error(
            'Shard doc #' +
              shard_id +
              ' does not exist.'
          );
        } else {
          const new_count = doc.data().count - 1;
          return t.update(shard_ref, { count: new_count });
        }
      });
    });
  });

Здесь, сравните с решением 1, так как у нас есть 3 осколкаЕсли вы хотите узнать количество документов в подгруппе subCollec, вам нужно прочитать только 3 документа.

Посмотрите в документации подробности инициализации распределенных счетчиков.Вы должны инициализировать один раз для каждой коллекции groupId (т.е. admin.firestore().collection('shards' + groupId))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...