Another would be to have a membership array of Group id’s in the User document. This option makes sense, but I’m not sure how easy a query would be to get all users who have group id foobar in their array.
If you are going to need to query both for a user’s group and a group’s users and will do that in more or less the same frequency, I’d say go for both of them and keep them in sync.
But I’d imagine, as your app data grows and you have hundreds/thousands of users for each group, you’ll be needing to query for a user’s group more freuently than you do for the users of a group.
If you find yourself needing both queries frequently, you may seek solutions like peerdb (which keeps relations in sync for you) or perhaps neo4j.
What aboat a third option: a separate membership collection. You could also store membership properties there, like role(s) or permissions in Group, start/end of membership, etc.
I think this scales much better. You can have indices on all properties.
In the above solution, the userId (user1) is base64-encoded so the id can be used in queries and updates (e.g., groups.PetsUnited.user1_id). The approach is laid out nicely here
How would you deal with a famous person joining your website? Imagine Kim Kardashian creating her profile and having 10 million followers. MongoDB has a hard 16MB document size limit. It would be better to extract followers into a separate collection.
I think it’s reasonable that your schema could change once you have a user with millions of followers. Optimizing for that ahead of time would be a mistake, IMO.
I think a separate collection works. I’ve seen recommendations for two separate collections, one for followers and another for followings where the _id fields are reversed. This would probably require a little extra on the operations side but it’ll lead to more flexibility and better scaling. I think the most interesting part of this solution is base64-encoding the userId field. Apparently drilling for mongo _id in deeply nested doc is challenging; nevertheless, I haven’t seen this approach recommended in meteor community. I’m a newbie, but I pay much attention to the model layer.
@sergiotapia I know this thread isn’t too old, but just wondering if you had a use case for bringing this idea up and which route you ended up taking. Trying to decide between these two structures right now as well…
I’m mostly interested in checking whether a user has permission to post in a group. So having a string array of the groups he’s a member of is simple to query.
And for listing out member of a group, I can also query like:
// Users who belong to group 'foo'.
db.users.find( { groups: "foo" } )
Associate using the group id, not the group name though.
That is what I am leaning towards as well. I have a count field on the group document that I $inc +1/-1 when members join/leave, so that I don’t have to query all of the users to get a member count on each group. Just curious if you have any other fields on the group document that make life easier?
Yeah, I also have that counter cache that is updated whenever someone joins or leaves a group, that’s a definite good idea. Other than that, I don’t have any other helper fields.