Utilize pivot to manage user roles and permissions in ExpressJS application using Mongoose

My user schema is structured as shown below

const userSchema = mongoose.Schema({
    username: {
        type: String,
        required: true,
    },
    first_name: {
        type: String,
        required: true,
    },
    last_name: {
        type: String,
        required: true,
    },
    email: {
        type: String,
        required: true,
    },
    password: {
        type: String,
        required: true,
    },
    otp: {
        type: String,
    },
    phone_number: {
        type: String,
        required: true,
    },
    resetPasswordToken: {
        type: String,
    },
    resetPasswordExpires: {
        type: Date,
    }
    
}, { timestamps: true });

role schema

import mongoose from 'mongoose';

const roleSchema = mongoose.Schema({
    name: {
        type: String,
        required: true
    },
}, { timestamps: true })


export default mongoose.model('Role', roleSchema);

and user role schema:

import mongoose from 'mongoose';

const userRoleSchema = mongoose.Schema({
    userId: {
        type: mongoose.Schema.Types.ObjectId,
        required: true,
        ref: "User",
        unique: true,
    },
    roleId: {
        type: mongoose.Schema.Types.ObjectId,
        required: true,
        ref: "Role",
        unique: true,
    }
}, { timestamps: true })

export default mongoose.model('UserRole', userRoleSchema);

I am looking for a more efficient way to retrieve the user object along with their corresponding role in Mongoose. Instead of relying on pivots, is there a simpler approach I can take? This is important because my design involves multiple objects connected through pivot tables.

User->userRole->Role Additionally;

User->userPermission->Permission

I understand that I could use the populate method for relationships, but only if I have the roles and permissions fields directly within the user schema referencing the role and permission schemas.

In essence, I need a cleaner way to link these schema objects without having to manually fetch the associated role information as illustrated below. My goal is to obtain a complete user object with the role name and also include permissions.

let user =  User.getRole(1); // find user
let userRole = UserRole.where('userId',1); // determine the user role
let role = Role.findOne(userRole.roleId); // get the specific role
user.role = role.name; // add role name to user object

The same concept applies to rolePermission pivots for associating roles with permissions and direct userPermission pivots.

Answer №1

If you're looking to combine collections in mongodb, the lookup feature is your friend.

  const userWithRoles = await User.aggregate([
    {
      "$match": {
        "_id": 1  // adjust as needed
      }
    },
    {
      "$lookup": {
        "from": "userRoles",  
        "localField": "_id",
        "foreignField": "userId",
        "as": "roles"
      }
    },
    {
      "$lookup": {
        "from": "roles",  
        "localField": "roles.roleId",
        "foreignField": "_id",
        "as": "roles"
      }
    }
  ])
})

Check out this playground for a demonstration.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to delete a section of the URL within an anchor tag prior to the #anchor

My webpage contains a link that looks like this: <li class="jump"><a href="http://example.com/#about">About Me</a></li> I am interested in using jQuery to eliminate the 'http://example.com/' section of any URL found with ...

The upcoming development does not involve creating an entire HTML webpage using on-demand static site generation (SS

I’m encountering a problem when utilizing getStaticPaths and getStaticProps to create an on-demand SSG for a sharing page. My setup involves Next v12.1.0 and React 17.0.2. After building a specific /[id] page, I can retrieve the data but the HTML output ...

Resizing tables dynamically using HTML and JavaScript

I am attempting to reproduce the functionality demonstrated in this example When dealing with a large table, I want it to resize to display 10 entries and paginate them accordingly. The only thing I require is the pagination feature without the search bar ...

Utilize JavaScript to redirect based on URL parameters with the presence of the "@ symbol"

I need help redirecting to a new page upon button click using a JS function. The URL needs to include an email address parameter. <form> <input type="email" id="mail" placeholder="ENTER YOUR EMAIL ADDRESS" requir ...

What steps can be taken to resolve the issue of a Node-express application serving server files via a

I'm currently experiencing an issue with my live server application. It seems that my node.js app is serving backend JavaScript code through a URL. I need to find a way to prevent it from serving these backend files. Interestingly, this problem doesn& ...

Is there a method to display a loading animation while the micro apps are being loaded in a single spa project?

Currently, I am working on a project using single spa and I need to implement a loader while my micro app is being loaded. Additionally, I also need the loader to be displayed when switching between these micro apps. Are there any methods to accomplish t ...

Ways to obtain the output of an If/Else statement

It seems like I might be missing something, but I am unsure of how to extract the result from an else-if statement. Take this code snippet that I've been working on for example: In this scenario, the output would read "It's warm!", and what I wa ...

simultaneous ajax requests - encountering issues in getting a response from the initial one

I'm in the process of developing a small "ping" tool to verify the connectivity of our two servers. Here is the snippet of JavaScript code I am using: var t1, t2, t3, t4; function jsContactServers() { ajaxServerStatusWWW(); ajaxServerStatus ...

Ways to focus on a specific div using JavaScript

I am attempting to create a 'snow' effect on the background of a particular div with a red border. Here is the code, but you can also view it here: <!-- language: lang-js --> var width = getWidth(); var height = getH ...

Next.js 13 app directory experiences 404 Not Found error due to dynamic routing issues

I recently built a straightforward to-do app using Next.js 13 paired with TypeScript. The process involved creating an array of objects, each comprising an id string and a name string. Subsequently, I iterated through the list and showcased the names withi ...

Encountering a CORS policy issue while attempting to retrieve data from an API

I have been attempting to retrieve data from the DHL API, however, I keep encountering issues due to CORS policy blocking the request. Even though I have configured the CORS policy on my backend server, the error persists. What could be the issue? Here ...

What is the best way to dynamically adjust the width of multiple divisions in Angular?

I am currently working on an angular project to create a sorting visualizer. My goal is to generate a visual representation of an array consisting of random numbers displayed as bars using divisions. Each bar's width will correspond to the value of th ...

Can you tell if there are any distinctions between the two code snippets?

Initial Code console.log('Begin'); // output 1 await axios({ method: 'post', url: '<HTTP_URL>' data: <SOME_DATA>, }).then ((response) => { // Performing some action... This may take a few seconds. con ...

choosing a specific element within an HTML string stored in a variable

I have a variable containing HTML string data like this: var htmlstring = "<div><div class='testdiv'>924422</div></div>" My goal is to extract the content of the div with a specific class, in this case .testdiv. How ca ...

Is it possible to prevent the text from appearing in the text box when a button is

I have successfully implemented a feature where clicking on the button (click on me) in HTML displays a textbox along with another button (show) on the screen. The text written in the textbox is visible when the show button is clicked. However, after the i ...

Implementing template loading on page load with state in AngularJS

When my application loads, I want the nested view list-patents.htm to be displayed. The main navigation is on my index.htm, featuring two nav items: transactions and patents. If you click on patents, two sub-menu items will appear: list patents and add p ...

Exploring the scope in JavaScript functions

Looking at this small code snippet and the output it's producing, I can't help but wonder why it's printing in this unexpected order. How can I modify it to achieve the desired output? Cheers, The desired result: 0 1 2 0 1 2 The actual r ...

Executing an Ajax request. Best method for transmitting various data elements:

I am currently attempting to perform an ajax call with multiple data inputs. When I send only one string of data, I use the following method: $.ajax({ url: "php/update_lastordning.php", type: "POST", data: "elId=" + elId }); To retrieve t ...

How can I disable a select element in Laravel 5?

Hey everyone! Currently using Laravel 5 and trying to style the "select" class as "selectpicker". I'm facing an issue where I want to disable or hide the selected option when clicked, as I'm creating a div with the option's content right b ...

VueJS waits until the loop is complete before executing a re-render

Check out this VueJS code snippet: new Vue({ el: '#app', data: { tiles: [ { isActive: false }, { isActive: false }, { isActive: false }, { isActive: false }, { isActive: false } ] }, methods: { ...