关于在 firebase firestore 中存储统计信息的建议

Advice on storing statistics in firebase firestore

在 firestore 中,我有包含字段、日期和样本计数的文档。

我想每周汇总一次按日期分组的统计数据,即所有相同日期的样本计数应该相加。

那么出于历史原因,我想将其存储在统计集合中。

我不确定我是否应该将结果存储在地图字段中,或者使用日期作为归档编号并使用 specimenCount 作为值。

最重要的是存储它以便于阅读历史记录。

使用日期作为文档 ID,使用样本计数作为值。 因此,对于今天 (28-08-2021) 添加的文档,您可以这样添加它

Future<void> storeAnalytics(dynamic data) async {
  await FirebaseFirestore.instance.collection("analytics").doc(data['id']).set(
      {'value': FieldValue.increment(data['value']), 'date': data['date']},
      SetOptions(merge: true));
  // I used fieldValue.increment incase you have multiple data for 1 day.
  // SetOptions(merge: true), will prevent overwriting data if it already exists
  // I added date to the document incase in the future you want to fetch 
  // between a particular date range (eg. data for the year 2021). Here you can
  // just use a where query.
}

// call the above function like this
// you can create a function that returns date (without hypen or slash)
// from regular date and for use as doc id
await storeAnalytics({'id': '28082021', 'value': 'xxx', 'date': 'put in date'});


// In the future, if you want the data, you can call it like this
Future<dynamic> getAnalytics(DateTime start, DateTime end) async {
  await FirebaseFirestore.instance
      .collection('analytics/')
      .orderBy('date', descending: true)
      .where('date', isGreaterThanOrEqualTo: start)
      .where('date', isLessThan: end).get();
}

在设备上执行此操作毫无意义,而是创建一个云函数来处理此操作。 Javascript 模板如下。

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

exports.onCreate = functions.firestore
  .document("/path-to-document/")
  .onCreate((snap, context) => {
    const value = snap.data();
    const specimentCount = value.value;
    const timestamp = value.date;
    const date = timestampToDate(timestamp);
    const id = timestampToDayId(timestamp);

    return db.doc("analytics/" + id)
      .set(
        { data: admin.firestore.FieldValue.increment(specimentCount), date },
        { merge: true },
      );
  });
// if your document can be updated and deleted, you can add a listeners for 
// that.

/**
 * Returns javascript date (YYYYMMDD) from firebase timestamp.
 * @param {timestamp} timestamp The firebase timestamp.
 * @return {Date} The javascript date.
 */
function timestampToDate(timestamp) {
  const date = timestamp.toDate();
  date.setHours(0);
  date.setMilliseconds(0);
  date.setMinutes(0);
  date.setSeconds(0);
  return date;
}

/**
 * Returns full id from firebase timestamp.
 * @param {timestamp} timestamp The firebase timestamp.
 * @return {String} The id.
 */
function timestampToDayId(timestamp) {
  const date = timestamp.toDate();
  let day = date.getDate();
  if (day < 10) day = "0" + day;

  let month = date.getMonth() + 1;
  if (month < 10) month = "0" + month;

  return date.getFullYear() + "" + month + "" + day;
}

使用云函数的一个优势是您可以使用 firestore 规则限制分析收集的写入。只允许读取(云函数不需要被授予 firestore 访问权限)。另一个好处是这个任务不会占用设备资源。