Reputation: 606
CONTEXT:
Suppose there are a products and orders collections on Firestore.
And an order has many products, that is (pseudo-schema):
products {
name: string
}
orders {
items: [{
product_id: (ref products)
quantity: number
}]
}
With these security rules:
match /products/{document=**} {
allow read, write: if request.auth != null;
}
match /orders/{document=**} {
allow read, write: if request.auth != null;
}
SCENARIO:
Now, suppose we have created the product A.
Then, we created the order 1 for the product A.
Next, suppose we delete the product A (which is already being used in the order 1) from the products collection.
This would let the order 1 still referencing the deleted product A.
QUESTION:
Is there a way of writing a Security Rule that prevents the deletion of products that are being used on orders?
Upvotes: 1
Views: 1571
Reputation: 40582
First of all, if the goal is just consistency, you can use Functions to delete the references to A so there is no broken linkage.
However, if you specifically want to prevent deletion while linked, you'll need a different strategy, as there is no way to query another path within security rules at present.
Denormalize: keep a list of references in the product
Something like this in your data:
"{product_id}": {
"name": "...",
"orders": {
"order_id": true
}
}
Would allow you to write rules like this:
function isAuthenticated() {
return auth != null;
}
function hasLinks(resource) {
return !resource.data.links;
}
match /products/{pid} {
allow delete: if isAuthenticated() && !hasLinks(request.resource);
}
Other ideas
Using Functions: My first instinct was a queue approach (you queue the delete to the server and the serve decides if there is a link to the product and either deletes it or rejects the request). But that wouldn't work with your current structure either since you can't query across subcollections to find references to the product in each order subcollection. You'd still need a denormalized list of orders to products to use for this (making this pretty much the same as my solution above).
Archive items instead of deleting them: There's probably not a strong need to actually delete items, so archiving them instead could avoid the whole problem set.
Upvotes: 1