【问题标题】:Make sure firestore collection docChanges keeps alive确保 firestore 集合 docChanges 保持活跃
【发布时间】:2021-04-29 23:10:45
【问题描述】:

最终解决方案在本文底部。

我有一个 nodeJS 服务器应用程序,它监听一个相当大的集合:

//here was old code

这工作得很好:这些是大量文档,服务器可以从缓存而不是数据库中为它们提供服务,这节省了我大量的文档读取(并且速度更快)。

我想确保,这个集合一直保持活力永远,这意味着如果没有发生变化,则重新连接。

有什么方法可以创造这种确定性吗?此服务器可能已在线多年。

最终解决方案:

  • 保存更改时间戳的数据库侦听器
export const lastRolesChange = functions.firestore
  .document(`${COLLECTIONS.ROLES}/{id}`)
  .onWrite(async (_change, context) => {
    return firebase()
      .admin.firestore()
      .collection('syncstatus')
      .doc(COLLECTIONS.ROLES)
      .set({
        lastModified: context.timestamp,
        docId: context.params.id
      });
  });
  • 检查服务器是否具有与数据库相同的更新时间戳记的逻辑。如果它仍在侦听,则应该有,否则刷新侦听器,因为它可能已停止。
import { firebase } from '../google/auth';
import { COLLECTIONS } from '../../../configs/collections.enum';

class DataObjectTemplate {
  constructor() {
    for (const key in COLLECTIONS) {
      if (key) {
        this[COLLECTIONS[key]] = [] as { id: string; data: any }[];
      }
    }
  }
}

const dataObject = new DataObjectTemplate();

const timestamps: {
  [key in COLLECTIONS]?: Date;
} = {};

let unsubscribe: Function;

export const getCachedData = async (type: COLLECTIONS) => {
  return firebase()
    .admin.firestore()
    .collection(COLLECTIONS.SYNCSTATUS)
    .doc(type)
    .get()
    .then(async snap => {
      const lastUpdate = snap.data();

      /* we compare the last update of the roles collection with the last update we
       * got from the listener. If the listener would have failed to sync, we
       * will find out here and reset the listener.
       */

      // first check if we already have a timestamp, otherwise, we set it in the past.
      let timestamp = timestamps[type];
      if (!timestamp) {
        timestamp = new Date(2020, 0, 1);
      }

      // if we don't have a last update for some reason, there is something wrong
      if (!lastUpdate) {
        throw new Error('Missing sync data for ' + type);
      }

      const lastModified = new Date(lastUpdate.lastModified);

      if (lastModified.getTime() > timestamp.getTime()) {
        console.warn('Out of sync: refresh!');
        console.warn('Resetting listener');
        if (unsubscribe) {
          unsubscribe();
        }
        await startCache(type);
        return dataObject[type] as { id: string; data: any }[];
      }
      return dataObject[type] as { id: string; data: any }[];
    });
};

export const startCache = async (type: COLLECTIONS) => {
  // tslint:disable-next-line:no-console
  console.warn('Building ' + type + ' cache.');
  const timeStamps: number[] = [];
  // start with clean array

  dataObject[type] = [];

  return new Promise(resolve => {
    unsubscribe = firebase()
      .admin.firestore()
      .collection(type)
      .onSnapshot(querySnapshot => {
        querySnapshot.docChanges().map(change => {
          timeStamps.push(change.doc.updateTime.toMillis());

          if (change.oldIndex !== -1) {
            dataObject[type].splice(change.oldIndex, 1);
          }
          if (change.newIndex !== -1) {
            dataObject[type].splice(change.newIndex, 0, {
              id: change.doc.id,
              data: change.doc.data()
            });
          }
        });
        // tslint:disable-next-line:no-console
        console.log(dataObject[type].length + ' ' + type + ' in cache.');
        timestamps[type] = new Date(Math.max(...timeStamps));
        resolve(true);
      });
  });
};

【问题讨论】:

    标签: node.js caching google-cloud-firestore


    【解决方案1】:

    如果您想确保您已完成所有更改,您必须:

    1. 在每个文档中保留一个lastModified 类型字段,
    2. 使用查询来获取自您上次查看以来我们修改过的文档,
    3. 在服务器上存储您上次查询的时间。

    与此无关,您可能还对最近推出的 serve bundled Firestore content 功能感兴趣,因为它是减少您必须对 Firestore 服务器执行的收费读取次数的另一种方法。

    【讨论】:

    • 谢谢,这些捆绑包非常有趣。但是,我确实需要这里的实时能力。它是关于管理用户的角色。使用 lastModified 的第一种方法确实很棒并且很有意义:我还可以创建一个云函数来侦听集合更改并仅使用时间戳更新单个文档,我可以检查它。
    • 是的,一个 lastModified 也可以。我只是注意到自己一直需要modifiedAtcreatedAt,所以我倾向于将它们添加到每个文档中。
    • 只是想知道您的方法:删除文档时会怎样?
    • 如果删除日期很重要,我建议将它们标记为已删除或保留墓碑集合,而不是实际删除它们。
    • 在 OP 中分享了我的最终解决方案。非常感谢您的见解。
    猜你喜欢
    • 1970-01-01
    • 2011-05-21
    • 2011-08-07
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多