在Firestore文档中添加时间戳

71

我是Firestore的新手。Firestore文档中提到...

重要提示:与Firebase实时数据库中的“推送ID”不同,Cloud Firestore自动生成的ID不提供任何自动排序功能。如果您想按创建日期对文档进行排序,应将时间戳作为文档字段进行存储。

参考链接:https://firebase.google.com/docs/firestore/manage-data/add-data

那么我需要在文档中创建键名为timestamp吗?还是说created就足以满足Firestore文档中的要求。

{
    "created": 1534183990,
    "modified": 1534183990,
    "timestamp":1534183990
}
18个回答

74
firebase.firestore.FieldValue.serverTimestamp()

就我所知,你想怎么称呼它都可以。然后你可以使用 orderByChild('created')。

当设置时间时,我大多数情况下使用 firebase.database.ServerValue.TIMESTAMP。

ref.child(key).set({
  id: itemId,
  content: itemContent,
  user: uid,
  created: firebase.database.ServerValue.TIMESTAMP 
})

1
是的,我只使用 FieldValue.serverTimestamp。但我想确保不强制要求将名称为“timestamp”的键存储。 - Vicky Thakor
1
由于您在调用orderBy时提供了键名,所以它应该可以运行。 - Saccarab
2
在Firestore中使用firebase.database.ServerValue.TIMESTAMP无法正常工作: - Valeri
1
只是 .sv: 时间戳已设置。 - Valeri
43
在Firestore中,获取时间戳应该使用firebase.firestore.FieldValue.serverTimestamp()而不是firebase.database.ServerValue.TIMESTAMP - Zvi Karp
显示剩余4条评论

55
使用 Firestore 的 Timestamp 类,firebase.firestore.Timestamp.now()
由于 firebase.firestore.FieldValue.serverTimestamp() 无法与 Firestore 的 add 方法一起使用。参考链接

2
谢谢!不要忘记在index.js的顶部添加const firebase = require('firebase-admin')以及在package.json中添加依赖项firebase-admin - Abner Escócio
当我尝试这样做时,会出现一个错误,提示:“无法读取未定义属性'now'”。请问您知道这种方法是否仍然适用吗? - Mel
Timestamp.now() 将返回当前浏览器时间,用户可能会更改它以绕过您的应用程序时间限制。 - FindOutIslamNow
在“firebase.firestore.FieldValue.serverTimestamp()”中找不到“firebase”。请建议我应该包含哪个软件包来解决它。谢谢。 - Kamlesh
@Kamlesh 如果你正在使用 Firebase v9.x,你应该 #import { serverTimestamp } from "firebase/firestore" 而不是尝试访问 firebase.firestore.etc。请参见 https://dev59.com/S1EG5IYBdhLWcg3wP39V - Aaron Campbell
显示剩余2条评论

11

没错,像大多数数据库一样,Firestore 并不会存储创建时间。为了按时间排序对象:

选项 1:在客户端创建时间戳(无法保证正确性):

db.collection("messages").doc().set({
  ....
  createdAt: firebase.firestore.Timestamp.now()
})

这里的一个重要限制是Timestamp.now()使用本地机器时间。因此,如果在客户端机器上运行此命令,则无法保证时间戳的准确性。如果您在服务器上设置此选项或者保证顺序不那么重要,那么这可能没问题。

选项2:使用时间戳标记:

db.collection("messages").doc().set({
  ....
  createdAt: firebase.firestore.FieldValue.serverTimestamp()
})

时间戳标记是一种令firestore服务器在第一次写操作时在服务器端设置时间的标记。

如果在写入该标记之前读取它(例如,在侦听器中),则除非您按照以下方式读取文档,否则它将为NULL:

doc.data({ serverTimestamps: 'estimate' })

使用以下类似的方式设置您的查询:

// quick and dirty way, but uses local machine time
const midnight = new Date(firebase.firestore.Timestamp.now().toDate().setHours(0, 0, 0, 0));

const todaysMessages = firebase
  .firestore()
  .collection(`users/${user.id}/messages`)
  .orderBy('createdAt', 'desc')
  .where('createdAt', '>=', midnight);

请注意,此查询使用本地机器时间 (Timestamp.now())。如果您的应用程序确实重视客户端使用正确的时间,您可以利用Firebase实时数据库的此功能:

const serverTimeOffset = (await firebase.database().ref('/.info/serverTimeOffset').once('value')).val();
const midnightServerMilliseconds = new Date(serverTimeOffset + Date.now()).setHours(0, 0, 0, 0);
const midnightServer = new Date(midnightServerMilliseconds);

11

使用Firestore获取实时服务器时间戳

import firebase from "firebase/app";

const someFunctionToUploadProduct = () => {

       firebase.firestore().collection("products").add({
                name: name,
                price : price,
                color : color,
                weight :weight,
                size : size,
                createdAt : firebase.firestore.FieldValue.serverTimestamp()
            })
            .then(function(docRef) {
                console.log("Document written with ID: ", docRef.id);
            })
            .catch(function(error) {
                console.error("Error adding document: ", error);
            });

}

你只需导入 'firebase',然后在需要的地方调用 firebase.firestore.FieldValue.serverTimestamp() 即可。但要小心拼写,它是 "serverTimestamp()"。在本例中,它将时间戳值提供给 'createdAt',当上传到 firestore 的产品集合时。


这个不起作用:尝试导入错误:'firebase / app'不包含默认导出(作为'firebase'导入)。 - Ben
1
@Ben 如果你正在使用 Firebase v9.x,你应该使用 #import { serverTimestamp } from "firebase/firestore" 而不是尝试访问 firebase.firestore.etc。请参见 https://dev59.com/S1EG5IYBdhLWcg3wP39V - Aaron Campbell
我已经有一段时间没有使用Firebase了,你应该知道Firebase会不断进行更改,这可能意味着导入路径的变化。我认为@AaronCampbell的解决方案应该会有所帮助。 - John Yepthomi

10

对于Firestore

ref.doc(key).set({
  created: firebase.firestore.FieldValue.serverTimestamp()
})

在“firebase.firestore.FieldValue.serverTimestamp()”中找不到“firebase”。请建议我应该包含哪个软件包来解决它。谢谢。 - Kamlesh
他不知道,因为他只是复制粘贴了答案。 - Jhourlad Estrella
请确保您已正确地包含了 Firebase 库。 - Venkat Kotra

2
这个解决方案对我很有用: Firestore.instance.collection("collectionName").add({'created': Timestamp.now()}); 在Cloud Firestore中的结果是:Cloud Firestore Result

1
这样做不行,因为系统日期时间可能会被用户手动更改。OP想要服务器DateTime而不是本地的DateTime。 - Akshay

2

文档并未建议任何字段的名称。你引用的部分只是在说明以下两点:

  1. Firestore自动生成的文档ID没有像实时数据库那样自然的基于时间排序。
  2. 如果您想要基于时间排序,请将时间戳存储在文档中,并使用它来排序查询。(您可以随意命名)

1

分享一下我在谷歌上搜寻了两个小时后得到的解决方法,针对 Firebase 9+ 版本

import { serverTimestamp } from "firebase/firestore";

export const postData = ({ name, points }: any) => {
  const scoresRef = collection(db, "scores");
  return addDoc(scoresRef, {
    name,
    points
    date: serverTimestamp(),
  });
};


1
根据文档,您可以“将文档中的字段设置为服务器时间戳,以跟踪服务器接收更新的时间”。
示例:
import { updateDoc, serverTimestamp } from "firebase/firestore";

const docRef = doc(db, 'objects', 'some-id');

// Update the timestamp field with the value from the server
const updateTimestamp = await updateDoc(docRef, {
    timestamp: serverTimestamp() // this does the trick!
});

1
我的工作是将文本进行翻译。这段内容与编程有关,需要翻译成中文,并使其更加易懂。请保留HTML标签,但不要进行解释。根据我的理解,这段话的意思是“我使用的方法就是从快照参数snapshot.updateTime获取时间戳”。
exports.newUserCreated = functions.firestore.document('users/{userId}').onCreate(async (snapshot, context) => {
console.log('started!     v1.7');
const userID = context.params['userId'];

firestore.collection(`users/${userID}/lists`).add({
    'created_time': snapshot.updateTime,
    'name':'Products I ♥',
}).then(documentReference => {
    console.log("initial public list created");
    return null;
  }).catch(error => {
    console.error('Error creating initial list', error);
    process.exit(1);
});

});


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接