Firestore 按服务器时间戳查询

时间:2021-03-01 05:34:39

标签: firebase google-cloud-firestore

是否可以使用服务器的时间戳过滤 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 函数来实际处理折扣(使用服务器时间戳可以轻松验证到期时间),因此系统时间不正确的用户仍然无法实际使用折扣代码。尽管如此,最好保证此类查询中的时间从一开始就不会显示过期代码。

3 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

我一直在考虑与您类似的问题。

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

众所周知,“firebase.firestore.FieldValue.serverTimestamp()”不能用于查询,用设备内置的Timestamp查询是非常不确定的。 (例如 currentTimestamp(), Date() 之类的东西)

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

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

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

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

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

反之,如果用户因为权限被拒绝等原因无法访问文档,则可以确定他是普通会员。

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

答案 2 :(得分:-2)

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

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

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

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