开发者问题收集

如何正确使用 Firestore 的 serverTimestamp 来设置正在订阅的文档的值?

2020-08-20
891

概述/环境:

  • react-native 项目 v0.61.5
  • 使用 react-native-firebase
  • 使用操作填充 redux 状态,通过 props 显示 firestore 数据

目标:

  • 监听文档集合
  • 使用 Firestore 的 FieldValue.serverTimestamp() 设置所述集合中文档的时间值
  • 在快照监听器中使用 serverTimestamp 的 toMillis() 函数

观察/错误:

  • 在所述集合中创建文档时,文档创建正常,显示正常
  • 在创建文档/时间值时,应用程序因调用 doc.get('time').toMillis() 位于快照侦听器内: TypeError: null 不是对象(评估“doc.get('time').toMillis()”)

在此处输入图像描述

到目前为止,我已经尝试了此处提到的所有建议: 为什么 Firestore 的“doc.get('time').toMillis”会产生 null 类型错误?

似乎没有什么可以解决这个问题崩溃。

这是快照监听器:

.onSnapshot({ includeMetadataChanges: true }, (querySnapshot) => {
    if (querySnapshot.metadata.fromCache && querySnapshot.metadata.hasPendingWrites) {
    // ignore cache snapshots where new data is being written
      return;
    }
    const messages = [];
    querySnapshot.forEach((doc) => {
        const estimateTimestamps = { serverTimestamps: 'estimate' }
        const msg = doc.data();
        msg.docId = doc.id;
        msg.time = doc.get('time', estimateTimestamps).toMillis();
        const timestamp = doc.get('time', estimateTimestamps);
        if (timestamp) {
          msg.time = timestamp.toMillis();
        } else {
          debugger
          console.error(doc.id + ' is missing "time" field!');
        }

        messages.push(msg);
    });
    dispatch({ type: types.LOAD_MSGS, payload: messages });
    resolve();
});

这是文档的创建方式:

const addMsg = (msg, userConvos) => {
    return firebase.firestore().collection('messages').add({
        time: firebase.firestore.FieldValue.serverTimestamp(),
        sender: msg.sender,
        read: false,
        userConvos: [userConvos.sender, userConvos.receiver],
        content: {
            type: 'msg',
            data: msg.text
        }
    });
};

我理解该值在短时间内可能为空,我需要一种方法来防止应用程序在此期间崩溃。

2个回答

错误将您指向此代码:

doc.get('time').toMillis()

它表示 doc.get('time') 返回 null,因此您无法对其调用 toMillis()

您链接到的问题的答案确切解释了原因。如果仍然不清楚,我建议再读一遍。如果服务器时间戳事件未到达服务器,则时间戳将为 null。

也许您想像这样检查时间戳是否为 null,而不调用 toMillis()

msg.isPending = doc.get('time') === null;
Doug Stevenson
2020-08-20

在 @DougStevenson 帮助我理解之后。有点令人困惑,但重要的是要理解侦听器一直在运行,因此一旦时间值可用,它就会被设置,因此不存在真正的性能问题。我重新制定了我的方法,它有效:

querySnapshot.forEach((doc) => {
     const estimateTimestamps = { serverTimestamps: 'estimate' }
     const msg = doc.data();
     msg.docId = doc.id;
     msg.time = doc.get('time', estimateTimestamps).toMillis();
     const timestamp = doc.get('time', estimateTimestamps)
     
     if (doc.get('time') !== null) {
       msg.time = doc.get('time').toMillis()
     }

     messages.push(msg);
 });
Jim
2020-08-20