在Firestore规则中比较文档时间戳记

时间:2019-03-15 14:46:09

标签: google-cloud-firestore firebase-security-rules

在编写和测试Firestore规则时遇到了一个奇怪的问题。这是我要实现的目标:

  • 启动应用程序时,用户将匿名登录。的 用户开始一个新游戏。
  • 我创建了一个“会话”,基本上只包含一个时间戳。
  • 玩家玩游戏,获得一定的高分,然后进入屏幕,将比分发送到全球高分列表。提交高分后,我会检查该玩家是否已有会话,并且是否已经过了足够长的时间以使高分被视为有效。

在客户端(javascript)上,我使用以下行在文档中发送时间戳:

firebase.firestore.FieldValue.serverTimestamp()

这是当前规则集。您会看到只有在新的higscore的createdAt晚于会话的createdAt时才能创建分数。

service cloud.firestore {
    match /databases/{database}/documents {
        function isValidNewScoreEntry() {
            return request.resource.data.keys().hasOnly(['createdAt', 'name', 'score']) &&
            request.resource.data.createdAt is timestamp &&
            request.resource.data.name is string &&
            request.resource.data.score is int &&
            request.resource.data.name.size() <= 20
        }

        match /highscores/{entry} {
            allow list: if request.query.limit <= 10;
            allow get: if true; 
            allow create: if isValidNewScoreEntry() &&
      request.resource.data.createdAt > get(/databases/$(database)/documents/sessions/$(request.auth.uid)).data.createdAt;
        }

        function isValidNewSession() {
            return request.resource.data.keys().hasOnly(['createdAt']) &&
            request.resource.data.createdAt is timestamp
        }

        match /sessions/{entry} {
            allow list: if false;
            allow get: if false; 
            allow create: if isValidNewSession();
            allow update: if isValidNewSession();
        }
    }
}

当我模拟/测试这些规则时,出现一个错误,提示我无法将“时间戳”与“地图”进行比较。我不知道为什么'createdAt'值是一个映射,但似乎get()方法返回的内容与预期的不同。

我的问题是:比较属性 createdAt 从新提交的条目到现有会话文档的属性 createdAt 的正确方法是什么?我试图按照上述规则进行操作。

This is what a'Score' entry look like This is what a 'Session' entry looks like

编辑:

我做了一些进一步的挖掘,发现这行有效:

if request.resource.data.createdAt.toMillis() > get(/databases/$(database)/documents/sessions/$(request.auth.uid)).data.createdAt.seconds * 1000;

这很清楚,不是两个createdAt都是相同的格式。最后一个似乎是具有“ seconds”和“ nanoseconds”属性的基本对象。我确定它源自Timestamp接口,但是由于none of the methods found here存在,因此它作为平面对象返回,并在尝试调用它们时给出错误。但是,“ seconds”属性确实存在于第二个时间戳上,但在第一个时间戳上不可访问。

1 个答案:

答案 0 :(得分:0)

我发现了为什么时间戳不符合我的预期,并被强制转换为“地图”。 仔细阅读文档后,我发现get()方法返回了resourceresource具有属性data:地图。因此,get()方法不会返回我期望的文档,而是返回一个平面JSON对象,该对象为我提供了在de database中找到的所有属性。

https://firebase.google.com/docs/reference/rules/rules.firestore

https://firebase.google.com/docs/reference/rules/rules.firestore.Resource