First, userGroups
can be misleading. It could mean "the groups of each user". If you don't have any other kinds of groups, you can call it just groups
.
In a similar scenario, I created a Cloud Function for every path that affects what a user should see.
const updateUserFunData = (path: string) => {
return functions.database.ref(path).onWrite(async (data, context) => {
// Download any required data, calculate what changes should be made,
// then use a multi-path update to save these changes, like this:
await rootRef.child('userFunData').update({
[uid1 + '/' + data1]: true, // or a complete copy of the data
[uid1 + '/' + data2]: null, // use null to delete
});
});
};
export const onUserGroupsChange = updateUserFunData('users/{uid}/groups');
export const onFunDataGroupsChange = updateUserFunData('someFunData/{dataId}/groups');
Then clients can read userFunData/$uid
to get their data IDs (and then get each funData
), and rules can check if userFunData/$uid/$dataId
exists, to allow or deny a read.
If you want to skip that intermediate funData IDs query and the synchronization of all the following queries, you can replace true
with a full copy of the data, add a trigger for the other db changes that should change that data, and have clients query only userFunData/$uid
, which should contain all the data they should see.
You commented that maintaining a per-user list of data would not be practical. You can maintain a per-group list of data, and have each user get the data of each of their groups. The rules would check if the user exists in the users of the group being read. You would have to save the users of each group (or the groups of each user) as a map instead of an array.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…