【问题标题】:Firestore query by server timestamp按服务器时间戳查询 Firestore
【发布时间】:2021-05-30 16:21:45
【问题描述】:

是否可以使用服务器的时间戳过滤 Firestore 查询?尝试执行以下查询时:

firebase.app.firestore()
  .collection('posts')
  .where('timestamp', '<=', firebase.firestore.FieldValue.serverTimestamp())

抛出以下错误。

FirebaseError: Function Query.where() called with invalid data. FieldValue.serverTimestamp() can only be used with update() and set()

我知道我可以使用new Date() 而不是FieldValue.serverTimestamp(),但如果有一种方法可以使用受信任的服务器时间戳进行查询,那就太好了。我的用例是带有到期日期的折扣代码集合,其中到期日期保存为 Firestore 时间戳。如果用户更改他们的系统时间,如果我依赖客户端日期进行过滤,则此查询可能会返回无效(过期)结果。我正在使用 Firebase 函数来实际处理折扣(使用服务器时间戳很容易验证到期),因此系统时间不正确的用户仍然无法实际使用折扣代码。尽管如此,最好保证此类查询中的时间从一开始就不会显示过期代码。

【问题讨论】:

    标签: firebase google-cloud-firestore


    【解决方案1】:

    我一直在思考一个和你类似的问题。

    回复晚了,但我会写一个解决方案,希望它会有所帮助

    如您所知,“firebase.firestore.FieldValue.serverTimestamp()”不能用于查询,用设备自带的Timestamp查询是非常不确定的。 (例如 currentTimestamp(), Date() )

    在这种情况下,解决方案可能是使用 Firestore 中的安全规则。

    就我而言,我使用该方法来限制用户。

    “suspesnsions_user”集合用于限制因欺诈使用用户而导致的成员资格。 (用户的会员资格必须在releasedTimestamp之前被暂停。)

    match /suspensions_user/{userId} {
        allow read : if request.auth.uid == userId && resource.data.releasedTimestamp > request.time
    }
    

    如果安全规则使用如下,如果用户可以通过相关的安全规则访问位于“suspensions_user/{userId}”的文档,则可以确定他处于丢失状态会员资格。

    反之,如果用户因为权限被拒绝等原因无法访问该文档,则可以确定他具有正常的会员资格。

    正如您在问题中所说,如果您将相应的安全规则应用于“/coupons/{id}”等文档以验证对优惠券的访问权限,则可以进行准确的验证。

    【讨论】:

      【解决方案2】:

      FieldValue.serverTimestamp() 是一个标志,不是真正的值——它指示 FireeStore 在写入操作期间使用当前服务器时间作为值。它不是一个真正的“价值”,你可以用它来代替“现在”。

      您正在考虑(并想要使用)的是 firebase.firestore.Timestamp.now(), (sp?) https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp ,它使用纪元时间(补偿时区)。更改他们的本地时钟不会解决这个问题 - 正如您可能在其他地方注意到的那样,大多数浏览器和服务(包括 Firestore)需要本地时钟才能相当准确以维持操作。如果您的用户/黑客充分破解他们的本地时钟以试图绕过您的规则,那么他们的 Firestore 服务将无法正常工作。

      【讨论】:

      • 不幸的是,我认为Timestamp.now() 方法也只使用本地日期:github.com/firebase/firebase-js-sdk/blob/…。不过,如果时间太短,您关于 Firestore 不起作用的观点是有效的。我会接受这个作为答案,因为它包含一些很好的信息,但我认为这里唯一的解决方案是让服务器参与进来(通过函数或其他方式)。
      【解决方案3】:

      为了保持我的日期比较准确,我会采取以下措施:

      let timestamp = new Date().toISOString();
      // "2021-03-01T11:10:51.392Z"
      

      如果您在 Firebase 函数(或客户端)中执行此操作,您将始终获得 ISO 格式 (ISO 8601) 的 UTC 时间

      这很棒,因为您可以创建简单的String comparisons of ISO 8601 日期字符串。

      【讨论】:

      • 我看不出使用 UTC 和 ISO-8601 对本地系统时钟不准确有何影响。
      猜你喜欢
      • 1970-01-01
      • 2020-10-22
      • 2020-12-26
      • 2018-11-27
      • 2021-04-19
      • 2020-01-26
      • 2020-10-24
      • 2020-07-10
      • 1970-01-01
      相关资源
      最近更新 更多