在编写和测试我的Firestore规则时,我遇到了一个奇怪的问题。这就是我想要实现的目标:
在客户端(javascript)上,我使用以下行在我的文档中发送时间戳:
firebase.firestore.FieldValue.serverTimestamp()
这是当前的规则集。您可以看到只有当新高分的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();
}
}
}
当我模拟/测试这些规则时,我收到一条错误消息,指出我无法将'timestamp'与'map'进行比较。我不知道为什么'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都是相同的格式。最后一个似乎是一个具有“秒”和“纳秒”属性的基本对象。我确定它源于Timestamp接口,但它会作为一个扁平对象返回,因为none of the methods found here存在并在尝试调用它们时出错。但是,“秒”属性确实存在于第二个时间戳上,但在第一个时间戳上无法访问。
我已经找到了为什么时间戳不是我的预期并被投射到'地图'。在深入了解文档后,我发现get()
方法返回resource
。 resource
有一个属性data
:地图。因此,get()
方法不会像我预期的那样返回文档,而是一个平坦的JSON对象,它为我提供了在de数据库中找到的所有属性。
https://firebase.google.com/docs/reference/rules/rules.firestore
https://firebase.google.com/docs/reference/rules/rules.firestore.Resource