I am trying to use the Firestore security rules to edit some data, as follows, with a transaction in Flutter:
Future sendRequest(uidSend, uidRec, pid, title) async {
final crSend = ChatRequest(uid: uidRec, pid: pid, title: title);
var _lsSend = List();
_lsSend.add(crSend.toJson());
final crRec = ChatRequest(uid: uidSend, pid: pid, title: title);
var _lsRec = List();
_lsRec.add(crRec.toJson());
final uMSendDocref = userMetadataCollection.document(uidSend);
final uMRecDocref = userMetadataCollection.document(uidRec);
Firestore.instance.runTransaction((transaction) async {
await transaction.update(uMSendDocref, <String, dynamic>{
"sentRequests": FieldValue.arrayUnion(
_lsSend,
),
});
await transaction.update(uMRecDocref, <String, dynamic>{
"receivedRequests": FieldValue.arrayUnion(
_lsRec,
),
});
});
}
Notice that user1 is trying to update both his/her own data, as well as user2's. However, I only want user1 to be able to update this single field of user2's. I make my Firestore rules as such:
match /userMetadata/{uid} {
allow read: if uid == request.auth.uid || uid == 'PREVIEW';
allow write: if uid == request.auth.uid && uid != 'PREVIEW';
match /receivedRequests {
allow read: if uid == request.auth.uid;
allow write: if request.auth != null && request.auth.uid != 'PREVIEW';
}
match /sentRequests {
allow read: if uid == request.auth.uid;
allow write: if request.auth != null && request.auth.uid != 'PREVIEW';
}
}
receivedRequests
(and sentRequests
) only require that a user has a non-null auth to edit, ie, any user should be able to edit. However, I get a permissions error when running my transaction. Why is that? Perhaps I am misunderstanding Firestore rules? Perhaps the transaction is trying to do a read? Any thoughts?
UPDATE:
I tried using a batch:
Future sendRequest(uidSend, uidRec, pid, title) async {
//update own uM with post
//update other uM with user
final crSend = ChatRequest(uid: uidRec, pid: pid, title: title);
var _lsSend = List();
_lsSend.add(crSend.toJson());
final crRec = ChatRequest(uid: uidSend, pid: pid, title: title);
var _lsRec = List();
_lsRec.add(crRec.toJson());
final uMSendDocref = userMetadataCollection.document(uidSend);
final uMRecDocref = userMetadataCollection.document(uidRec);
var batch = Firestore.instance.batch();
batch.updateData(uMSendDocref, <String, dynamic>{
"sentRequests": FieldValue.arrayUnion(
_lsSend,
),
});
batch.updateData(uMRecDocref, <String, dynamic>{
"receivedRequests": FieldValue.arrayUnion(
_lsRec,
),
});
return await batch.commit();
}
Still does not work. Something is either incredibly unintuitive with Firestore, or there is a serious bug.
Another thing to note: some of the userMetadata might not currently have the fields that are being updated.
I only want user1 to be able to update this single field of user2's.
A general way of allowing updation of only certain fields can be with checking diff of request.resource.data
with resource.data
.
Example documents that need to be updated have 3 field: name, city, standingBalance. We want anyone to change standingBalance but only the corresponding user to change his name and city.
The below example is considering that user1 should have complete write
access to user1's sendRequest
& only single field update
access to user2's receivedRequests
, there won't be much change in other scenarios.
match /userMetadata/{uid} {
allow read: if uid == request.auth.uid || uid == 'PREVIEW';
allow write: if uid == request.auth.uid && uid != 'PREVIEW';
match /receivedRequests/{req} {
allow read: if uid == request.auth.uid;
allow write: if uid == request.auth.uid;
allow update: if uid == request.auth.uid
|| (request.resource.data.keys().hasOnly(['name','city','standingBalance'])
&& request.resource.data.name == resource.data.name
&& request.resource.data.city == resource.data.city
&& request.resource.data.standingBalance != resource.data.standingBalance
&& request.auth.uid != null
)
}
match /sentRequests/{req} {
allow read: if uid == request.auth.uid;
allow write: if request.auth != request.auth.uid || request.auth.uid != 'PREVIEW';
}
Checking with hasOnly
ensures that no other key is added to the document. Also, I am unaware of what 'PREVIEW' is so do verify the rules yourself.
Having a fieldsChanged
variable in firestore rules would be a good feature request ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With