I have two entities, projects and users. These are modeled in Rails using Mongoid with two Document instances, User and Project.
In this system, one user can create one project, but many users can follow many projects. For example, as user_id 1 I’ve created project_id 1. But user_ids 10, 11, 40, and 60 all follow project_id 1. I need to represent a many-to-many relationship between users and projects, and represent a specific user_id as the creator of the project, to assign him editing rights.
Practically speaking, when a user logs-in, he needs to be able to see all projects that he is following, including any that he created, commingled with other projects created by other users. His special creator status wont influence this list at all. When a user looks at a specific project, he needs to be able to view all users following a project, and if he’s a creator, he can add new followers and delete existing ones.
In a RDBMS I would represents this with tables users, projects and a users_projects join table with a flag of is_creator. This would easily let me select which projects a user can see, and which users are followers, including which users are creators, of projects.
Mongoid supports many-to-many relationships, but unlike in an RDBMS there’s no way for me to put a flag on the relationship. Instead, I’m thinking I’ll add a creator field to the projects document, which will contain a link back to an _id field on the users document.
The user->projects relationship might look like this
class User
has_and_belongs_to_many :projects
end
class Project
has_and_belongs_to_many: users
end
But I can’t figure out how to map the creator->created_projects relationship. I believe I can reference a user creator in Project like belongs_to :creator, :class_name => 'User' but I’m not sure how to set up the other side.
How best can I model these relationships in Mongoid?
create an embedded document which holds all followers with their user_id and their username so you won’t have to query the follower’s usernames.
The benefits:
The downside:
If a user changes his name, you’ll have to update all his “followships” but how often
do you change your name compared to how often you lookup your followed projects 😉
If you have many thousand followers per project you may reach the document limit of 16mb
user.rb
project.rb
follower.rb
How to work with it:
PS: If you want a simpler solution, you could just embedd an array of ObjectIDs (user_ids) in the project and use the atomic updates
$addToSetand$pullAllto add/remove a follower. But you’d need an extra query likeUser.where(:user_id.in => @project.follower_ids)(assuming the array is calledfollower_ids) to grab all users and their names 😉