英文:
Firestore rules stop listener
问题
为了我的Firebase项目,我已经创建了以下的Firestore规则:
match /games/{gameDoc=**} {
allow read, write: if resource.data.playerOne == request.auth.uid
|| resource.data.playerTwo == request.auth.uid;
}
这个规则按预期工作,然而我的问题是,我设置了监听器来监听受这些规则影响的文档。当文档被更改或创建时,监听器会被调用,但当文档被删除时,监听器不会触发。据我了解,问题源于删除操作后没有playerOne或playerTwo字段,因此规则拒绝通知监听器。是否有任何解决方法?
编辑:
客户端(Unity)上的监听器:
DocumentReference docRef = FirebaseFirestore.DefaultInstance.Collection("games").Document(game.gameID)
docRef.Listen(snapshot => {
Debug.Log("Game data changed");
if (snapshot.ToDictionary() == null) // 游戏已删除
{
dataManager.gameList.Remove(dataManager.gameList.Find(g => g.gameID == snapshot.Id));
} else
{
OnGameDataChanged(snapshot.ToDictionary());
}
// 更新用户界面
FindObjectOfType<GUIManager>().gameListGUI.DisplayGames();
});
当我将规则更改为true
时,监听器会被通知。
英文:
For my Firebase project I have created following Firestore rule:
match /games/{gameDoc=**} {
allow read, write: if resource.data.playerOne == request.auth.uid
|| resource.data.playerTwo == request.auth.uid;
}
The rule works as intended, however my problem is that I set up listeners to documents that are affected by these rules. When a document is changed or created, the listener is called but when a document is deleted, the listener is not triggered. As far as I understand, the problem derives from the fact that after the delete operation there is no playerOne or playerTwo field, therefore the rules reject to notify the listeners. Is there any way around this?
EDIT:
Listener on Client-Side (Unity):
DocumentReference docRef = FirebaseFirestore.DefaultInstance.Collection("games").Document(game.gameID)
docRef.Listen(snapshot => {
Debug.Log("Game data changed");
if(snapshot.ToDictionary() == null) // Game got deleted
{
dataManager.gameList.Remove(dataManager.gameList.Find(g => g.gameID == snapshot.Id));
} else
{
OnGameDataChanged(snapshot.ToDictionary());
}
// Update UI
FindObjectOfType<GUIManager>().gameListGUI.DisplayGames();
});
When I change the rules to true, the listener is notified.
答案1
得分: 1
如果您想检测删除操作,您需要使用change.ChangeType
对象,如文档中所解释的。然后,您将能够获取已删除文档的数据。
Query query = db.Collection("...").WhereEqualTo(...);
ListenerRegistration listener = query.Listen(snapshot =>
{
foreach (DocumentChange change in snapshot.GetChanges())
{
if (change.ChangeType == DocumentChange.Type.Added)
{
Debug.Log(String.Format("New: {0}", change.Document.Id));
}
else if (change.ChangeType == DocumentChange.Type.Modified)
{
Debug.Log(String.Format("Modified: {0}", change.Document.Id));
}
else if (change.ChangeType == DocumentChange.Type.Removed)
{
Debug.Log(String.Format("Deleted: {0}", change.Document.Id));
}
}
});
但是,需要考虑一个重要因素:规则不是筛选器。因此,您的查询必须与您的安全规则匹配。
此外,正如l1b3rty在他的评论中提到的,当写入数据时,request.resource
变量包含文档的未来状态。请参考文档。
英文:
If you want to detect the deletions you have to use the change.ChangeType
object as explained in the doc. And you’ll be able to get the data of the deleted doc.
Query query = db.Collection("...").WhereEqualTo(...);
ListenerRegistration listener = query.Listen(snapshot =>
{
foreach (DocumentChange change in snapshot.GetChanges())
{
if (change.ChangeType == DocumentChange.Type.Added)
{
Debug.Log(String.Format("New: {0}", change.Document.Id));
}
else if (change.ChangeType == DocumentChange.Type.Modified)
{
Debug.Log(String.Format("Modified: {0}", change.Document.Id));
}
else if (change.ChangeType == DocumentChange.Type.Removed)
{
Debug.Log(String.Format("Deleted: {0}", change.Document.Id));
}
}
});
}
}
However, there is an important element to take into account: Rules are not filters. So your query must match your security rule.
Also, as mentioned by l1b3rty in his comment, when writing data, the request.resource
variable contains the future state of the document. See doc.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论