Nodejs mongoDB多对多关系,如何设计数据库?

Nodejs mongoDB多对多关系,如何设计数据库?

角色表,权限表,用户表,他们之间都是多对多的关系,在mongoDB中可以如何设计文档结构呢?

5 回复

在MongoDB中处理多对多关系时,可以通过嵌套引用或使用独立的集合来管理关联。对于角色表、权限表和用户表之间的多对多关系,我们可以采用一种灵活的设计方法。以下是一个示例设计:

角色表(Roles)

每个角色可以拥有多个权限,并且一个权限可以被多个角色共享。

{
  "_id": ObjectId("5f9c8d4b27a3e10e0c7f1d23"),
  "name": "admin",
  "permissions": [
    { "$ref": "permissions", "$id": ObjectId("5f9c8d4b27a3e10e0c7f1d24"), "$db": "mydatabase" },
    { "$ref": "permissions", "$id": ObjectId("5f9c8d4b27a3e10e0c7f1d25"), "$db": "mydatabase" }
  ]
}

权限表(Permissions)

每个权限可以被多个角色拥有。

{
  "_id": ObjectId("5f9c8d4b27a3e10e0c7f1d24"),
  "name": "view_users"
},
{
  "_id": ObjectId("5f9c8d4b27a3e10e0c7f1d25"),
  "name": "edit_users"
}

用户表(Users)

每个用户可以属于多个角色,并且一个角色可以包含多个用户。

{
  "_id": ObjectId("5f9c8d4b27a3e10e0c7f1d26"),
  "username": "john_doe",
  "roles": [
    { "$ref": "roles", "$id": ObjectId("5f9c8d4b27a3e10e0c7f1d23"), "$db": "mydatabase" }
  ]
}

示例代码

添加权限到角色

const roleModel = mongoose.model('Role', roleSchema);
const permissionModel = mongoose.model('Permission', permissionSchema);

async function addPermissionToRole(roleId, permissionId) {
  const role = await roleModel.findById(roleId);
  role.permissions.push({
    $ref: 'permissions',
    $id: permissionId,
    $db: 'mydatabase'
  });
  await role.save();
}

添加用户到角色

const userModel = mongoose.model('User', userSchema);

async function addUserToRole(userId, roleId) {
  const user = await userModel.findById(userId);
  user.roles.push({
    $ref: 'roles',
    $id: roleId,
    $db: 'mydatabase'
  });
  await user.save();
}

解释

  • 嵌套引用:我们通过 $ref$id 字段来引用其他集合中的文档。
  • 查询优化:为了高效地获取用户的角色和权限信息,可以在应用层进行多次查询或使用聚合框架进行复杂查询。
  • 数据一致性:由于MongoDB不支持事务,确保数据一致性的责任落在了应用程序层面。

这种方法既保持了灵活性,又能够有效地管理复杂的多对多关系。


这样写不知道你能不能明白。。。如果你会基本的查询应该想想就明白了。。。 users (hash) userid:1 roleA : 1 (set) add , edit , del

我想问的是具体的设计思路以及如何查询的问题,比如多对多可以用link,也可以用DBRef,还有就是单个文档大小限制的问题也需要考虑? 不知这个如何 https://www.npmjs.org/package/mongoose-relationship

在MongoDB中处理多对多关系通常可以通过嵌套引用或使用中间集合来实现。对于你的需求(角色、权限、用户之间的多对多关系),推荐使用中间集合的方法。

设计思路

  1. 用户表 (users)

    • 每个用户可能属于多个角色。
    • 用户可以拥有多个权限,但这些权限是通过角色间接关联的。
  2. 角色表 (roles)

    • 每个角色可以包含多个权限。
    • 每个角色可以分配给多个用户。
  3. 权限表 (permissions)

    • 权限是独立的实体,可以被多个角色共享。
  4. 中间集合 (user_rolesrole_permissions)

    • user_roles: 用于记录用户与角色的关系。
    • role_permissions: 用于记录角色与权限的关系。

示例设计

用户表 (users)

{
    "_id": ObjectId("650d9b1c123456789abcde"),
    "name": "Alice",
    "email": "alice@example.com"
}

角色表 (roles)

{
    "_id": ObjectId("650d9b1c123456789abcdf"),
    "name": "Admin"
}

权限表 (permissions)

{
    "_id": ObjectId("650d9b1c123456789abcda"),
    "name": "read"
}

中间集合: 用户角色 (user_roles)

{
    "_id": ObjectId("650d9b1c123456789abcdb"),
    "userId": ObjectId("650d9b1c123456789abcde"),
    "roleId": ObjectId("650d9b1c123456789abcdf")
}

中间集合: 角色权限 (role_permissions)

{
    "_id": ObjectId("650d9b1c123456789abcdd"),
    "roleId": ObjectId("650d9b1c123456789abcdf"),
    "permissionId": ObjectId("650d9b1c123456789abcda")
}

示例查询

查询用户 Alice 的所有权限:

const userId = ObjectId("650d9b1c123456789abcde");

db.user_roles.find({ userId }).toArray().map(userRole => {
    return db.role_permissions.findOne({ roleId: userRole.roleId }).then(rolePermission => {
        return db.permissions.findOne({ _id: rolePermission.permissionId });
    });
}).then(permissions => {
    console.log(permissions);
});

总结

这种设计方式通过两个中间集合将多对多关系解耦,既保留了灵活性,也方便了数据管理和查询。在实际应用中,可以根据业务需求调整字段和索引以优化性能。

回到顶部