In my local environement using the firebase emulator, I have the following rule that raises a FirebaseError: Property managers is undefined on object. for 'list'
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /businesses/{business} {
allow read: if request.auth != null && request.auth.uid in resource.data.managers;
}
}
}
If I test the same rule on the rules Playground, it works correctly (Simulated read allowed
)..
To prove I have the managers property defined and available, if I change the rule to if true
, I can loop on the list with the following local data:
// code
...
.then((snap) => snap.forEach((doc) => console.log(doc.id, " => ", doc.data())))
// output
VzaU8rX8HOgejk0fyOFK => {..., managers: Array(1)}
What am I doing wrong?
Thank you !
UPDATE
This is the code I would like to have the rule applied on:
useEffect(() => {
db.collection("businesses")
.where("slug", "==", params.slug)
.get()
.then((snap) => {
if (!snap.empty) {
// slug is supposed to be unique, so I retrieve the first and only element
const doc = snap.docs[0]
setBusiness({ id: doc.id, data: doc.data() })
setState({ ...state, loading: false, data: true })
} else {
setState({ ...state, loading: false, error: "Business not found" })
}
})
.catch((error) => {
console.log("Error getting document:", error)
setState({ ...state, loading: false, error: "Error getting document" })
})
}, [])
Your rule works in the console simulator because it's only testing the read of a single docyment at a time. Your client code, however, is performing a query for multiple documents, which is different. One very important thing to know is that security rules are not filters (be sure to read that, and this). Security rules will not remove documents from the result set if the rule would reject a document. Instead, the query must be able to fetch all document allowed by the rule, or the rule will reject the query entirely.
A query must explicitly have the same filter as required by the rules. Your rule requires that the query only filter for documents where the current user is in the managers array field. Therefore, it the query must be more like this:
db.collection("businesses")
.where("slug", "==", params.slug)
.where("managers", "array-contains", uid)
Where uid
is the current user's uid.
At first, Could you try db.collection("businesses").get("VzaU8rX8HOgejk0fyOFK");
?
Secondly, Did you use array-contains
, in
, or array-contains-any
as where()
method comparison operation?
If you not, Coud you try the following code?
ex.
db.collection("businesses").where("managers", "in", uid)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
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