Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongo DB Design for user favourites (Pros and cons)

Tags:

mongodb

I need to have 2 API to

1) Retrieve a list of clothes (while checking which items are the user's favourites, and mark it with a heart shape)

2) Retrieve a list of user's favourite clothes

enter image description here

How should I store user favourites?

What I've figured out so far:

Embed all user's ID in each clothing item in "Clothes" document. And keep an array of user's favourite in "User" document. To find out which clothes is a user's favourite we will do a match between "Clothes" and "User" document by leveraging the ID field.

Clothes collection:

{
    "id" : "clothesID01",
    "images": [
        {"imgUrl": "https://s3-ap-1.amazonaws.com/rental/img1.png"},
        {"imgUrl": "https://s3-ap-1.amazonaws.com/rental/img2.png"},
        {"imgUrl": "https://s3-ap-1.amazonaws.com/rental/img3.png"}
    ],
    "brand" : "Halo",
    "title" : "Cheryl Dress",
    "retailPrice" : {
        "currency": "USD",
        "amount": 447 
    },
    "description":"Halo pieces are xxxx",
    "favorites" : [
        {"userId" : "user01"},
        {"userId" : "user02"}
    ],
    "isPremium" : true,
    "publishedDate" : "2019-04-04T06:12:46.839+00:00"

    ...
}

User collection:

{
    "id": "user01",
    "phoneNumber": "+123456789",
    "favourites":[
        {"clothesId" : "clothesID01"},
        {"clothesId" : "clothesID04"}
    ]

    ...
}

Base on the Rules of thumb for mongoDB Design , in rule 3,

if there are more than a few thousand documents on the “many” side, don’t use an array of ObjectID references

The "clothes" document favourite might consist of about 100k users (fingers crossed) which might not be suitable to use an array of ObjectID references.

What's the remedy for this?

like image 222
user1872384 Avatar asked Apr 27 '19 08:04

user1872384


People also ask

What are the disadvantages of MongoDB?

Cons: Data size in MongoDB is typically higher due to e.g. each document has field names stored it. less flexibity with querying (e.g. no JOINs) no support for transactions - certain atomic operations are supported, at a single document level.

Why you should not use MongoDB for your project?

MongoDB would not be well suited for applications that need: Multi-Object Transactions: MongoDB only supports ACID transactions for a single document. SQL: SQL is well-known and a lot of people know how to write very complex queries to do lots of things.


1 Answers

First of all, you have no need to store the favorite data in the clothes collection at all. In addition to the issues you identified, you will have a race condition whenever two users update favorite the same clothing item simultaneously.

Instead, only store the user's favorites in the User collection, then highlight the hearts during the rendering phase if the ClothesID matches the User's list of favorites.

Second, use a dictionary hashmap for more performative lookups, rather than a list which will require searching every item.

 {
    "id": "user01",
    "phoneNumber": "+123456789",
    "favourites": {
       "clothesID01": true, 
       "clothesID04": true
    }
} 

When you want to know if a clothesID is a favorited, you can check if

if (user.favourites[clothesID] === true)

This does not require iterating over every item in an Array, instead you are checking just one specific location in memory.

So the direct queries you would use:

1) Retrieve a list of clothes (while checking which items are the user's favourites, and mark it with a heart shape)

const user = await db.User.findOne(ObjectId(userId));
const clothes = await db.Clothes.find(query).toArray();
for(let article of clothes) {
  if(user.favourites[article.clotheId]) {
    // display full heart
  } 
}

2) Retrieve a list of user's favourite clothes

const user = await db.User.findOne(ObjectId(userId), {favourites:true});
const favouriteIds = Object.keys(user.favourites);
const favourites = await db.Collection.find({_id: {$in: favouriteIds}}).toArray();
like image 122
XaxD Avatar answered Sep 29 '22 12:09

XaxD