Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to model many-to-many relationships in MongoDB (for a MySQL user)

I come from a MySQL background and am trying to wrap my head around MongoDB. In particular, I'm struggling to conceptualize how I should model n:n relationships the "Mongo way."

For this example, let's say we have two collections: users and interests. We need to be able to represent or query for several things in our data:

  • User's interests
  • User's rating of interest, e.g. "like" or "dislike"
  • Users with a given interest
  • Counter (which can be incremented/decremented) of each rating of the interest
  • Interest name

In MySQL, I would have created a users_interests table indexed on both user IDs and interest IDs. For the counter, I would have had separate columns for each rating type, and each time a user rated/un-rated an interest, done a transaction to ensure that the counts were never false.

I've tried reading about some schema designs, but to no avail.

Can you help a lost soul find the way?

like image 473
Josh Smith Avatar asked Nov 30 '11 17:11

Josh Smith


2 Answers

Great question. Let me first outline a bit of how the N:N relationship works then I'll go into detail on each of your bullet points.

N:N in MySQL normally you have your pivot table associating between your user and interests (user_interests table). In mongo you do this a bit differently. You still have a users and interest collection, however instead now, you store a list of keys under interests for a user. SO something like this:

User Collection {
      "name":"Josh",
      "user":"jsmith",
      "interests":[
           {
            "_id":12345,
            "rating":"like"
           },
           {..}..
      ]
}

By storing your interests in a list which is keyed off on your interest table, you can perform each of the actions you require. If you wanted to do a query you'd od it based on the ID which is in the interest table then do a query using the $in modifier.

Now for your interests collection I'd do the following:

User Interest {
      "_id":objectId
      "label":"Swimming",
      "count":intValue
}

When adding an interest to a users document, the count variable would then depend on the definition of your ratings. If you're storing your ratings in a separate area (or in logic), then the value you assigned to them would be what you relate then to the int value in interest. IE: User rates it meh (which has a value of 1) then you would add 1 to the count value.

Hopefully this is helpful and has at the very least brought about some other ideas on how to structure it!

Best of luck, remember MONGO IS AWESOME.

like image 199
Petrogad Avatar answered Sep 21 '22 17:09

Petrogad


To maintain a global count of the ratings of each interest, you will need a separate and independent collection where you update (add or subtract) ratings using atomic update operators as and when like/dislike actions for interests are performed by users.

You can store each User's interest as an array of sub-documents within the User collection itself.

The JSON structure of this data would be something similar to:

db.User
{
    name: 'joe',
    ....,
    interests : [{ name: 'swimming', rating: 10},
              { name: 'cooking', rating: 22 }
              ]
}

Now you can query on the internal keys using:

> db.User.find( { "interests.name" : "cooking" } )

This will return users who have a particular interest.

like image 45
Dayson Avatar answered Sep 17 '22 17:09

Dayson