0

I want to make a social game for Android. I am using NoSQL Based Database (MongoDB) and I am using NodeJs. I am using Android-Volley library to make POST and GET requests. But I am stucked on something, I need to see friends of friends or send some game requests or friend requests from one user to another. However, I am still struggling about how to design the database-model.

Firstly,

{     
  "user1": 
  {           
      "friendsList": [ {"user2" : {id:"2", ...}}]        
  },
  "user2":{
      "friendsList": [ {"user1" : {id:"1", ...}}]        
  }
}

Or Second Approach,

 {
  "user1" : { 
     "friendsList": [ 
         { 
          "user2" : { 
             "friendsList":[ {"user1" : { ... } } ] 
         }, 
         ...
      ]
   }
}

So basically, what I am asking that, should I include the whole "user" object in a list or should I keep only the id numbers. If I keep the id numbers, should I make another request for the given Id numbers in order to show the profile etc. I want to reduce down to requests ( I think that I need to make another request for given id number) that's why, I need your help.

Thank you for your time.

  • Why would you have an ID for a friend of a friend? I think you normally don't collect such info. I mean, your user will register and get an ID but their friends will not have to register (if it is a single player game). – NoChance Mar 4 at 9:44
  • @NoChance It is not a single player game, you have to send a game request to another friend and all users were registered before and they can find/send/recieve game requests. What I am thinking as an ID (it is a primary key from database) because I can make another requests of user which has that unique id. – engineur Mar 4 at 9:48
  • 2
    In this case, you normally use the ID only not the entire user object for reference to a friend because, the information of the friend could change between the registration time and establishing friendship relation. – NoChance Mar 4 at 10:25
  • @NoChance Thank you for your comments! I am just wondering that for other ID numbers should I make an another request for each ID number? For example user1 wants to check the profile of user3 which is a friend of user2. So basically user1->user2->user3. – engineur Mar 4 at 11:33
  • The example JSON is mangled and not valid. Looks like you have an array of objects in some places, but there are no { and } delimeters – Greg Burghardt Mar 4 at 13:33
0

I'll try to explain why the second option is not a good approach to your problem (and the first approach with a RDBMS would be a rather simple as others have mentioned).

Also, I'm not following any JSON notation, I'll just name the users full information as Ux and the ids as x.


  • Suppose you have 2 users (U1 and U2 with ids 1 and 2, respectively) and you decide to nest them. Then you'd have something like:

[ {U1, friends:{U2}}, {U2, friends:{U1}} ] - Here, you have both users information duplicated.

  • Now, we add a 3d user which is friends with both U1 and U2.

[ {U1, friends:{U2, U3}}, {U2, friends:{U1, U3}}, friends:{U3, {U1, U2}} ] - Here, as you might have noticed, you have more repetition.

If you had N users, you'd replicate them N times.

  • But I'm ignoring something: If follow the first approach user representation strictly, things get worse because U1 is friends with U2 which is friends with U1, cyclic! Should we nest it as well? When should we stop?

Finally, when you go for approach 1, you will only need references to the other objects. Data won't be duplicated and you won't need to nest anything.

If you have N users, you will hava at most a list of N+1 friends IDs without duplication. :)

And then you can use these IDs to access the other users.

0

should I include the whole "user" object in a list or should I keep only the id numbers

Only you know the answer. When working with MongoDB, the design of the schema is guided by how data is going to be accessed and maintained.

  • What documents are going to be retrieved oftener?
  • What documents (or pieces of information) are usually retrieved together?
  • What documents change at the same time for the same reasons?
  • What's the relationship between documents? Do we need to retrieve relationships every time we retrieve documents? If yes, do we need all the data? Just part of it?
  • Given N different related documents. What's their growth ratio? Do they grow in the same orders of magnitude?
  • How are documents going to be indexed?
  • Etc.

The schema is designed upon this kind of premises and it reflects the data structure that makes your application as performant as possible.

And all of this, bearing in mind that MongoDB transactions are atomic. Even when executing updateMany, insertMany, etc.

As for nesting documents of the same collection. It results in a waste of resources, as for space as for CPU. A single user updating its data would result in countless atomic transactions. Why? Because that user updating its data would have to update its data in every nested document where it's located at. Every single time. Same goes for deletes.

If I keep the id numbers, should I make another request for the given Id numbers in order to show the profile etc.

Not necessarily

db.player.insertMany([
{"id": "1", "name": "Cheewaka", "friends":["2","3","4"]},
{"id": "2", "name": "Han Solo", "friends":["1","3", "4"]},
{"id": "3", "name": "Luke Skywalker", "friends":["2","5"]},
{"id": "4", "name": "Leia Organa", "friends":["1","2"]},
{"id": "5", "name": "Anakin Skywalker", "friends":["3"]}
]);
db.player.aggregate([
{
    $lookup: {
       from: "player",
       localField: "id",
       foreignField: "friends",       
       as: "friendsProjection",       
   }
},
{
    $project: { "id":1, "name":1, "friendsProjection.id":1, "friendsProjection.name":1 }
}
]);
{
    "_id" : ObjectId("5ca5bf858a4acb43d5020583"),
    "id" : "1",
    "name" : "Cheewaka",
    "friendsProjection" : [ 
        {
            "id" : "2",
            "name" : "Han Solo"
        }, 
        {
            "id" : "4",
            "name" : "Leia Organa"
        }
    ]
}

Note how the lookup has solved the problem of Luke not being friends of Chewee; you could not do that with nested documents. Well, you could, but you would end up with a lookup similar to the one above. Note also the $project over friendsList, it brought only the information I need for the case.

Q: But what If I want the friendsProjection of the users within the array?

A: You don't, because you might end up eventually fetching the whole collection with a single query. Imagine Facebook fetching the whole graph of users' relationships (2.7 billion people) every time a random user refresh its wall.

Further readings

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.