Need help in modelling the following Entity Diagram in MongoDB

Context: I need some tips to model the parts shaded in blue in the entity diagram shown above.

The Entities User, Channel, Course and Topic and their relations are already modelled in the database by collections of the same name.
The are modelled in the following simple manner:

  1. User contains an array of references to the Courses.
  2. A Course contains an array of references to the Topics
  3. A Topic cotntains an array of references to the Channels

Question: How can I now model the new many to many has Notification Settings For Relationship between

  1. The User and the Channel
  2. The User and the Topic
  3. The User and the Course

as shown in the diagram.

Note that this relation also contains an attribute called s1, s2, s3 for simplicity’s sake.

The reason for asking this question is, that I have a Query that a User does everytime when he/she uses the application.

Everytime a Course is fetched, I want to fetch :

  1. The Topic’s in the Course
  2. the value of the attribute s2 for every Topic from step 1
  3. The Channels connected to each Topic from step 1
  4. The s3 attribute for every Channel in step 3

AND I want to send the result in the following manner to the Front end:
Basically, Channels that belong to particular topic are put in an array and sent with the respective topics object. Example below for illustrative purpose

{
    First 2 properties are the Course Properties
    "_id": "647666fb1296a965aa631cfa",
    "name": "Front end fundamentals",
    "s1": true,
    "topics": [
        {
            "topicId": "647856b01296a965aa6321cd",
            "s2": true,
            "_id": "647856b01296a965aa6321cd",
            "name": "UX Design",
            "courseId": "647666fb1296a965aa631cfa",
            "userId": "64766648ef43feb4849b2cea",
            "channels": [
                {
                    "topicId": "647856b01296a965aa6321cd",
                    "channelId": "647856cd1296a965aa63221e",
                    "s3": true,
                    "_id": "647856cd1296a965aa63221e",
                    "name": "Introduction",
                    "description": "",
                    "courseId": "647666fb1296a965aa631cfa",
                    "userId": "64766648ef43feb4849b2cea",
                },
                {
                    "topicId": "647856b01296a965aa6321cd",
                    "channelId": "64785a2a1de1c55ba02df099",
                    "s3": true,
                     "_id": "64785a2a1de1c55ba02df099",
                    "name": "Lecture 1",
                    "description": "",
                    "courseId": "647666fb1296a965aa631cfa",
                    "userId": "64766648ef43feb4849b2cea",
                  },


                {
                    "topicId": "647856b01296a965aa6321cd",
                    "channelId": "43534tg4566trretwert23",
                    "s3": true,
                     "_id": "64785a2a1de1c55ba02df099",
                    "name": "Lecture 1",
                    "description": "",
                    "courseId": "647666fb1296a965aa631cfa",
                    "userId": "64766648ef43feb4849b2cea",
                },
  
                {
                    "topicId": "647856b01296a965aa6321cd",
                    "channelId": "64785a2a1de1c5dasfrewtdfsg35",
                    "s3": true,
                     "_id": "64785a2a1de1c55ba02df099",
                    "name": "Lecture 1",
                    "description": "",
                    "courseId": "647666fb1296a965aa631cfa",
                    "userId": "64766648ef43feb4849b2cea",
                },
            ],
            "createdAt": "2023-06-01T08:28:32.154Z",
            "updatedAt": "2023-06-01T08:28:32.154Z",
            "__v": 14
        },

        {
             "topicId": "647ef264e2c03f930e3b3854",
            "s2": true,
            "_id": "647856b01296a965aa6321cd",
            "name": "UX Design",
            "courseId": "647666fb1296a965aa631cfa",
            "userId": "64766648ef43feb4849b2cea",
            "channels": [
                {
                    "topicId": "647ef264e2c03f930e3b3854",
                    "channelId": "7893214hjbf801346y",
                    "s3": true,
                    "_id": "dasdf78032343nkjhkjnkj234",
                    "name": "test 2:35",
                    "description": "Teaching about xAPI Notifications once again",
                    "courseId": "647666fb1296a965aa631cfa",
                    "userId": "64766648ef43feb4849b2cea",
                },
                {
                    "topicId": "647ef264e2c03f930e3b3854",
                    "channelId": "23574934057934057",
                    "s3": true,
                    "_id": "648705fdf5cf921815ae5960",
                    "name": "test 2:35",
                    "description": "Teaching about xAPI Notifications once again",
                    "courseId": "647666fb1296a965aa631cfa",
                    "userId": "64766648ef43feb4849b2cea",
                }
            ],
        }

}

Possible Solution
This is the solution that I have come up with and it is working but I am not sure if this is the best possible way to model it.

I introduced a new Collection called Notification Settings in my database.

It has the following shape:

const BlockingNotifications = new Schema({
  userId: {
    type: Schema.Types.ObjectId,
    ref: "user",
    required: true,
    index: true,
  },
  courseId: {
    type: Schema.Types.ObjectId,
    required: true,
    ref: "course",
    index: true,
  },
  s1: { type: Boolean },

  topics: [
    {
      topicId: {
        type: Schema.Types.ObjectId,
        ref: "topic",
      },
     s2 : { type: Boolean },
    },
  ],
  channels: [
    {
      topicId: {
        type: Schema.Types.ObjectId,
        ref: "topic",
      },
      channelId: {
        type: Schema.Types.ObjectId,
        ref: "channel",
      },
     s3 :{ type: Boolean },
   }
  ],

})

A particular document of the above collection, would for a particular Course and a User, contain all the Topics, and Channels of the Course along with their respective attributes (s1, s2, s3) .

When I make the query for a particular course, I first look for the document of the above collection with the userId equal to the User making the query.

and using a aggregation pipeline, I perform a $lookup on all the Topics and Channels.

Then once again using aggregation I arrange the channels into the respective topic to which they belong. I do this using the $map Operator. To figure out which channel belongs in which topic. The result looks like the first code snippet.

I would like to know if this is the best possible way to model this data and Query this data.

If needed I can also post the aggregation pipeline if interested.

Hi @Ebrahim_Karjatwala and welcome to MongoDB community forums!!

Firstly, thank you for sharing all the information in detail.
In order to make the most accurate recommendation for the data modelling of the shared ER diagram, it would be greatly beneficial if you could provide additional information regarding the following:

Instead of adding reference to other entity, MongoDB gives you the leverage of using Embedding in MongoDB which would definitely help in efficient query processing.
Referencing is however, one another way to create the relationships but in order to build it between the collections, but you might end up creating expensive operations like $lookup which in turn might end up being a slow query.

MongoDB’s flexible data modelling allows us to design the database schema to optimise query execution time and efficiency, based on the specific use case. By carefully considering the data model, we can structure your data for efficient querying and performance.
To ensure the best performance, you can leverage MongoDB’s data modelling capabilities and discuss your use case requirements. This way, we can design a schema that aligns with your application’s needs and maximises query execution efficiency.

This would make the query you wish to have more easier to fetch the data from the collections.

This could be one solution but this way your design might completely follow a relational approach and you might miss on feature and flexibility that MongoDB provides.

However, in saying so, the data modelling always depends on the way the query has to be executed in the application.

Suggesting the best possible solution would be difficult without knowing how you’re expecting the data to grow over time.
As I mentioned earlier, if the collection is expected to grow significantly, you might need to evaluate the performance impact of your current approach as $lookup may become expensive in such conditions.

For more assistance, you can also reach out to the MongoDB consulting who can guide you with the appropriate designs and implementation methods which would be best suited according to your use case.

I would also recommend you to follow our MongoDB Courses and Trainings | MongoDB University for further understanding and learnings.

Do reach out to us if you have any further queries.

Regards
Aasawari

1 Like