我的目标
我希望只允许用户更新其他用户文档中的特定字段。
我的用户文档
/* BEFORE */
{
id: 'uid1',
profile: { /* a map of personal info */ },
connectedUsers: {
uid2: true,
uid3: true,
}
}
/* AFTER */
{
id: 'uid1',
profile: { /* a map of personal info */ },
connectedUsers: {
uid2: true,
uid3: true,
uid4: true, // <--- added.
}
}
请求
const selfUserId = 'uid4';
db.runTransaction(function(transaction) {
return transaction.update(userDocRef).then(function(userDoc) {
if (!userDoc.exists) { throw "Document does not exist!"; }
transaction.update(userDocRef, 'connectedUsers.${selfUserId}', true);
});
}
我对规则工作原理的理解:
request.resource.data
是在更改后整个目标文档。对于
update
操作,以上内容仍然有效。我不太明白文档中所说的:
对于仅修改文档字段子集的更新操作,
request.resource
变量将包含待处理文档状态。
我的规则: (见下面的更新)
function existingData() { return resource.data }
function expectedData() { return request.resource.data }
- 检查更新后是否添加了请求者的
uid
。
function isAddingRequester() {
return expectedData().connectedUsers[requesterId()] != null
}
- 检查更新后是否只添加了
1
或0
个项目到connectedUsers
。如果请求者已经在列表中,则为0
。
function isAddingOneAtMost() {
return expectedData().connectedUsers.size() == existingData().connectedUsers.size() + 1
|| expectedData().connectedUsers.size() == existingData().connectedUsers.size()
}
- 检查更新后用户文档的所有其他字段是否未更改。
function isNotChangingOtherFields() {
return expectedData().id == existingData().id
&& expectedData().profile == existingData().profile
}
我的问题
我对Firestore规则的理解正确吗?上面提到的文档中的“pending document state”是什么意思?
我的规则实现反映了我的意图吗?在搜索并学习模拟器可能存在错误后,我感到困惑。
在我的
isNotChangingOtherFields
函数中,我能否使用==
运算符直接比较profile
对象?
更新-2018/01/17 3PM
已删除existingData()
和expectedData()
。
function isAddingRequester() {
return request.resource.data.connectedUsers[requesterId()] != null
}
function isAddingOneAtMost() {
return (request.resource.data.connectedUsers.size() == resource.data.connectedUsers.size() + 1)
|| (request.resource.data.connectedUsers.size() == resource.data.connectedUsers.size()) // NOTE: if the requester is already in the list.
}
function isNotChangingOtherFields() {
return request.resource.data.profile == resource.data.profile
&& request.resource.data.id == resource.data.id
}
function isNotAddingOtherFields() {
return request.resource.data.size() == resource.data.size()
}
调试结果
有趣的是,在模拟器和生产环境中,结果并不相同。
// PASSED in simulator & production:
allow update: if isAddingRequester();
// PASSED in simulator but NOT production:
allow update: if isNotChangingOtherFields();
// PASSED in simulator but NOT production:
allow update: if isNotAddingOtherFields();
// FAILED in both simulator AND production:
allow update: if isAddingOneAtMost();
// NOTE: inserted 2 mock data before update.
// PASSED in simulator:
allow update: if resource.data.connectedUsers.size() == 2;
// FAILED in simulator:
allow update: if request.resource.data.connectedUsers.size() == 3;
// PASSED in simulator:
allow update: if request.resource.data.connectedUsers.size() == 1;
问题
如果request.resource
是更新后的文档,为什么request.resource.data.connectedUsers.size()
为1,而不是3(2个现有+1个新添加)?
相关发现(来自模拟器)
如果我有一个函数:
expectedData() { return request.resource.data }
我得到了一些意想不到的结果:
// PASSED:
allow update: if request.resource.data.id == expectedData().id;
// FAILED if the order is changed.
allow update: if expectedData().id == request.resource.data.id;
expectedData()
是什么?另外:代码有什么问题吗?它拒绝了你想要允许的写入吗?还是允许了你想要拒绝的写入? - Frank van Puffelen