I have a Firestore database on Google Firebase with "village" collection inside of it. I want to limit read/write functionality for each document for specific user with their uuid as the document key.
I have added the rule to the "Rules" tab in Firestore, but I'm when I'm trying to fetch data I get an error saying that I don't have permisions to the Firestore...
This is my rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /village/{villageId} {
allow read, write: if request.auth != null && request.auth.uid == villageId;
}
}
}
This is the code snippet which returns data successfully if I remove my rule from Firestore:
useEffect(() => {
const collectionRef = collection(db, "village");
const q = query(collectionRef, orderBy("timestamp", "desc"));
const unsubscribe = onSnapshot(q, (querySnapshot: any) => {
setVillage(
querySnapshot.docs.map((doc) => ({
...doc.data(),
id: doc.id,
timestamp: doc.data().timestamp?.toDate().getTime(),
}))
);
});
return unsubscribe;
}, []);
Your current query is requesting all villages, and ordering them by their timestamp. Because your user can only access their own village, you need to change your query to only target what they have access to (remember that Firestore Security Rules are not filters).
To update your code to work with the rules you defined, you need to switch from a query of all villages, to just their village.
const currentUser = ...;
useEffect(
() => {
if (!currentUser) return; // signed out
const villageDocRef = doc(db, "village", auth.currentUser.uid);
return onSnapshot(
villageDocRef,
{
next: (docSnapshot) => { // don't use the any type
if (!docSnapshot.exists()) { // don't forget to handle missing data
return setVillage(null);
}
docData = docSnapshot.data();
setVillage({
...docData,
id: docSnapshot.id,
timestamp: docData.timestamp?.toMillis() // shorter than .toDate().getTime()
});
},
error: (err) => {
// TODO: Handle Firestore errors
console.error('Failed to get village data ', err);
setVillage(null);
}
}
);
},
[currentUser] // rerun when user changes
);