Reputation: 103
I have a users collection where each document contains a name field and and an access map.
"users" :[
{
"mHbVq5TUY7brlleejClKm71NBGI2": {
"name": "Bob Johnson",
"access": {
"X0w1VaVIljR1Nc5u3Sbo" : true
}
}
]
I would like the Firestore rules to allow creation of a new document only if it doesn't already exist and only if the person performing the action has had their email verified. For the update, only the user owning that node can perform the update, the name must be a string, and the access map should not be able to be changed. I tested my update and create rules in the simulator and they worked as expected. However, when I run a .set() it completely overwrites my entire node and removes the access map which I cannot have happen. I assume that a .set() is actually performing an update and thus meeting my update criteria. So, how do I prevent someone from completely overwriting my node. Thanks in advance...code below.
---CODE PERFORMING OVERWRITE
db.collection("users").doc("mHbVq5TUY7brlleejClKm71NBGI2").set(
{
name: "Bill Swanson",
}
).catch(err => {
console.log(err.message)
})
---RULES
function incomingData() {
return request.resource.data
}
function emailVerified() {
return request.auth.token.email_verified;
}
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
function userExists(user_Id) {
return exists(/databases/$(database)/documents/users/$(user_Id));
}
allow create: if !userExists(userId) && emailVerified();
allow update: if request.auth.uid == userId
&& !('access' in incomingData())
&& request.resource.data.name is string;
allow read: if request.auth.uid != null;
}
}
}
Upvotes: 1
Views: 1055
Reputation: 576
When using set(), If you're not sure whether the document exists, pass the option to merge the new data with any existing document to avoid overwriting entire documents.
Here's how to pass the option to merge the update with the existing document.
db.collection("users")
.doc("mHbVq5TUY7brlleejClKm71NBGI2")
.set(
{
name: "Bill Swanson"
},
{
merge: true
}
).catch(err => {
console.log(err.message)
});
Hope this helps.
Upvotes: 1