添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Imagine Facebook’s group feature, using MongoDB. What would be the best way to structure the data?

Main operations on this data will be find users who belong to the group and determine if user X is a member of the group.

One option would be to have an array of strings in the Group document.

name: "Pets United", members: [ "iuahsdfuhasdfasdf", "qwefqwefqwefqweff", "ioeroigkergnknmkm"

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.

firstName: "Sergio", age: 27, groups: [ "iuahsdfuhasdfasdf", "qwefqwefqwefqweff", "ioeroigkergnknmkm"

Which one do you guys think is better if I expect a group to have thousands of users?

Looks like the second option would be the best approach here unless I’m misreading the documentation.

https://docs.mongodb.org/manual/reference/operator/query/in/#use-the-in-operator-to-match-values-in-an-array

So a query to find user’s who joined group foo would be:

db.users.find( { groups: { $in: ["foo"] } } )
          

I think it’s basically equivalent. Also, the query above can be shortened to this:

db.users.find( { groups: "foo" } )

You only need $in if you have an array of groups and you want users who are in one or more of them.

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.

firstName: "Sergio", age: 27, followers: [ { "user2_id" : { name:Sashko, groups: [ 'PetsUnited' , 'PetsDivided' ] } } ], groups: { "PetsUnited": {"user1_id": {name: Sergio}, "user2_id": { name: Sashko} }, "PetsDivided": {"user1_id": {name: Sergio}, "user2_id": { name: Sashko} }

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

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.

Hi @vigorwebsolutions, I ultimately went with the second option.

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.