【问题标题】:Add timestamp in Firestore documents在 Firestore 文档中添加时间戳
【发布时间】:2018-08-14 17:33:03
【问题描述】:

我是 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
}

【问题讨论】:

    标签: firebase google-cloud-firestore


    【解决方案1】:
    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 
    })
    

    【讨论】:

    • 是的,我只使用FieldValue.serverTimestamp。但我想确保存储名称为 timestamp 的密钥不是强制性的
    • 它应该锻炼,因为您在调用 orderBy 时提供了键名。
    • 在 Firestore 中使用 firebase.database.ServerValue.TIMESTAMP 不起作用:
    • 只需 .sv:时间戳已设置。
    • 在 Firestore 中获取您应该使用 firebase.firestore.FieldValue.serverTimestamp() 而不是 firebase.database.ServerValue.TIMESTAMP 的时间戳
    【解决方案2】:

    使用 Firestore 时间戳类,firebase.firestore.Timestamp.now()

    由于 firebase.firestore.FieldValue.serverTimestamp() 不适用于 firestore 中的 add 方法。 Reference

    【讨论】:

    • 谢谢!不要忘记 index.js 顶部的 const firebase = require('firebase-admin') 和 package.json 中的依赖 firebase-admin
    • 谢谢,这应该是最佳答案!
    • 当我尝试这个时,我收到一条错误消息:“无法读取未定义的属性‘现在’”。您知道这种方法是否仍然有效?
    • Timestamp.now() 将返回当前浏览器时间,用户可能会更改该时间以解决您的应用时间限制
    • “firebase”未在“firebase.firestore.FieldValue.serverTimestamp()”中找到。请建议我应该包含哪个包来解决它。谢谢。
    【解决方案3】:

    对于 Firestore

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

    【讨论】:

    • “firebase”未在“firebase.firestore.FieldValue.serverTimestamp()”中找到。请建议我应该包含哪个包来解决它。谢谢。
    【解决方案4】:

    使用 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()”。在此示例中,它在上传到 Firestore 的产品集合时为“createdAt”提供时间戳值。

    【讨论】:

    • 这不起作用:Attempted import error: 'firebase/app' does not contain a default export (imported as 'firebase').
    【解决方案5】:

    没错,与大多数数据库一样,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);
    

    【讨论】:

      【解决方案6】:

      文档并未建议您的任何字段的名称。您引用的部分只是说两件事:

      1. 为 Firestore 自动生成的文档 ID 不像在实时数据库中那样具有基于时间的自然排序。
      2. 如果您想要基于时间的排序,请在文档中存储一个时间戳,然后使用它来对您的查询进行排序。 (您可以随意称呼它。)

      【讨论】:

        【解决方案7】:

        这个解决方案对我有用:

        Firestore.instance.collection("collectionName").add({'created': Timestamp.now()});

        Cloud Firestore 中的结果是: Cloud Firestore Result

        【讨论】:

        • 这不起作用,因为用户可以手动更改系统日期时间。 OP 想要服务器 DateTime 而不是本地的。
        【解决方案8】:

        为 Swift 4 Timestamp(date: Date()) 试试这个

        let docData: [String: Any] = [
        "stringExample": "Hello world!",
        "booleanExample": true,
        "numberExample": 3.14159265,
        "dateExample": Timestamp(Date()),
        "arrayExample": [5, true, "hello"],
        "nullExample": NSNull(),
        "objectExample": [
            "a": 5,
            "b": [
                "nested": "foo"
            ]
        ]
        ]
        db.collection("data").document("one").setData(docData) { err in
        if let err = err {
            print("Error writing document: \(err)")
        } else {
            print("Document successfully written!")
        }
        }
        

        【讨论】:

          【解决方案9】:

          它与我一起工作的方式,只是从快照参数中获取时间戳 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);
          });
          

          });

          【讨论】:

            【解决方案10】:

            我正在使用 Firestore 存储来自带有 Python 的 Raspberry PI 的数据。管道是这样的:

            Raspberry PI(使用 paho-mqtt 的 Python)-> Google Cloud IoT -> Google Cloud Pub/Sub -> Firebase Functions -> Firestore。

            设备中的数据是 Python 字典。我将其转换为 JSON。 我遇到的问题是 paho-mqtt 只会将数据作为字符串发送(发布),而我的数据字段之一是时间戳。这个时间戳是从设备中保存下来的,因为无论数据最终何时存储在数据库中,它都能准确地说明测量的时间。

            当我发送我的 JSON 结构时,Firestore 会将我的字段“时间戳”存储为字符串。这不方便。所以这里是解决方案。

            我在由 Pub/Sub 触发的 Cloud Function 中进行转换,以使用 Moment 库写入 Firestore 进行转换。

            注意:我在 python 中获取时间戳:

            currenttime = datetime.datetime.utcnow()

            var moment = require('moment'); // require Moment 
            function toTimestamp(strDate){
              return parsedTime = moment(strDate, "YYYY-MM-DD HH:mm:ss:SS");
             }
            
            exports.myFunctionPubSub = functions.pubsub.topic('my-topic-name').onPublish((message, context) => {
            
              let parsedMessage = null;
              try {
                parsedMessage = message.json;
            
                // Convert timestamp string to timestamp object
                parsedMessage.date = toTimestamp(parsedMessage.date);
            
                // Get the Device ID from the message. Useful when you have multiple IoT devices
                deviceID = parsedMessage._deviceID;
            
                let addDoc = db.collection('MyDevices')
                                .doc(deviceID)
                                .collection('DeviceData')
                                .add(parsedMessage)
                                .then ( (ref) => {
                                  console.log('Added document ID: ', ref.id);
                                  return null;
                                }).catch ( (error) => {
                                  console.error('Failed to write database', error);
                                  return null;
                                });
            
              } catch (e) {
                console.error('PubSub message was not JSON', e);
              } 
            
              // // Expected return or a warning will be triggered in the Firebase Function logs.
              return null;  
            });
            

            【讨论】:

              【解决方案11】:

              Firestone 方法不起作用。使用 java.sql.Timestamp 中的 Timestamp 并且不要转换为字符串。然后 firestone 正确格式化它。例如标记 now() 使用:

              val timestamp = Timestamp(System.currentTimeMillis())
              

              【讨论】:

              • 此解决方案存在日期操作问题
              【解决方案12】:

              在 Firestore 中存储时间的多种方式

              1. firebaseAdmin.firestore.FieldValue.serverTimestamp() 方法。将文档写入 Firestore 时将计算实际时间戳。
                存储时看起来像这样:

              1. firebaseAdmin.firestore.Timestamp.now() 方法。
                存储时看起来像这样:

              对于这两种方法,下次您获取数据时,它将返回 Firestore Timestamp 对象:

              因此,您首先需要将其转换为原生 js Date 对象,然后您可以对其执行类似 toISOString() 的方法。

              export function FStimestampToDate(
                timestamp:
                  | FirebaseFirestore.Timestamp
                  | FirebaseFirestore.FieldValue
              ): Date {
                return (timestamp as FirebaseFirestore.Timestamp).toDate();
              }
              
              1. 存储为 unix 时间戳 Date.now,它将存储为数字,即 1627235565028,但您将无法在 firestore db 中将其视为可读日期。
                要查询这个 Firestore 字段,您需要将日期转换为时间戳,然后再查询。

              2. 存储为new Date().toISOString(),即"2021-07-25T17:56:40.373Z",但您将无法对此执行日期范围查询。

              我更喜欢第二种或第三种方式。

              【讨论】:

              • 假设所有日期使用相同的时区,#4 生成的字符串实际上是可排序的。 IE。对于 ISOString,字母数字排序与日期排序完全相同。这意味着您可以使用这些字符串进行范围查询。
              【解决方案13】:

              斯威夫特 5.1

              ...
              "dateExample": Timestamp(date: Date()),
              ...
              

              【讨论】:

              • 使用时间戳最重要的一点是在服务器上生成它。通过使用 Date() 对其进行初始化,您会生成一个客户端时间戳,如果您的计算机日期设置错误,则不会生成正确的日期。如果您的应用程序依赖时间戳来订购数据,这将不起作用。改用接受的答案
              猜你喜欢
              • 2020-11-24
              • 2022-01-09
              • 1970-01-01
              • 2019-12-10
              • 2020-12-26
              • 2020-06-23
              • 2018-11-07
              • 2015-02-16
              • 2019-08-06
              相关资源
              最近更新 更多