在MongoDB中插入时如何检查引用?

在MongoDB中插入时如何检查引用?,mongodb,Mongodb,假设我有用户和角色。每个用户都属于一个角色。我想这样设计数据库: 收集用户: { "name":"user1" "role":"admin" } 集合角色: { "name":"admin" "privileges":[] } { "name":"user" "privileges":[] } 以后我可以添加更多角色或编辑任何角色的权限 我的问题是:在插入新用户时,如何检查“角色”字段是否具有有效值(这意味着角色集合中存在匹配文档) 我应该在应

假设我有用户和角色。每个用户都属于一个角色。我想这样设计数据库:

收集用户:

{
    "name":"user1"
    "role":"admin"
}
集合角色:

{
    "name":"admin"
    "privileges":[]
}
{
    "name":"user"
    "privileges":[]
}
以后我可以添加更多角色或编辑任何角色的权限

我的问题是:在插入新用户时,如何检查“角色”字段是否具有有效值(这意味着角色集合中存在匹配文档)

我应该在应用程序中检查此引用吗?在mongodb服务器端有这样做的方法吗


让我们假设编辑权限是一项经常性的操作。

因为您可以免费获得_id的索引,所以您应该将用户引用到角色_id

{
    _id: ObjectId("55f5128e6e5daa295293e31e"),
    name: "admin"
},
{
    _id: ObjectId("55f5128e6e5daa295293e31f"),
    "name":"user"
}
并根据每个用户分配权限

{
    "name":"user1",
    "role":ObjectId("55f5128e6e5daa295293e31e"),
    "privileges":[]
}
更好的是,去掉角色集合

{
    "name":"user1",
    "role": "admin",
    "privileges":[]
}

编辑:


Chris Ma“如果我有1k用户的角色为“admin”,现在我想为所有管理员添加一个权限。然后我必须编辑1k用户。对吗?我们有更好的解决方案吗?”

如果您可以想象,解决方案将是相同的:

集合“角色”


我认为你是本末倒置

对于数据建模,您应该首先了解您对数据的问题。对于用户、角色和权限关系,问题是显而易见的

对于给定的用户,权限是什么

只要每个角色的权限不超过几个100k,您的角色模型就应该相当简单

{
  _id: "roleName",
  description: "a role",
  privileges:[
      "someService:someAction:someInstance",
  ]
},
{
  _id: "admin",
  description: "Administrator",
  privileges:[
      "adminService:*:*",
  ]
}
我们有一个给定的用户,具有

{
  _id: "foo",
  roles: ["roleName","admin"]
}
为了获得给定用户“foo”(您以前以
user
的身份加载该用户)的权限,我们执行以下操作

var user_privileges = db.roles.aggregate([
  { $match:{ _id:{ $in: user.roles} } },
  { $unwind: "$privileges" },
  { $group:{ _id: null, $push:{ "forAllRoles": "$privileges" } }
]}
这将生成一个结果文档,如

{ _id: null, forAllRoles:[
    "adminService:*:*",  
    "someService:someAction:someInstance"
  ]
}
检查权限现在变得容易了

var permission_needed = "adminService:*:*"

if(user_privileges.forAllRoles.indexOf(permission_needed) > -1){
  console.log("Yay, admin!");
  doSomeAdminStuff();
} else {
  console.log("Don't you dare again, user!");
}
由于我们通过
角色来查找特权。_id
(已编制索引),因此聚合应该非常有效,因为我们在处理之前将文档限制为很少

如果要向角色添加权限,这很简单

db.roles.update(
  { _id: "roleName" },
  { $addToSet: { privileges: [ "otherService:*:someInstance" ] } }
)

hth

如果需要检查,请在插入用户之前查询集合。@Michelem它可以工作,但效率不高。这是在应用程序端完成的。两次操作将有两次网络延迟。如果我们可以在mongodb服务器端进行检查会更好。如果我有1k个用户的角色为“admin”,那么现在我想为所有管理员添加一个权限。然后我必须编辑1k用户。对吗?我们有更好的解决方案吗?删除角色集合似乎不正确-作为一名用户管理员(分配权限),我希望有一个可用角色列表可供选择。不过,这取决于10次中有9次这样做是正确的。每个文档有16MB,如果您认为会超过16MB,请将它们分开。如果您需要独立于其他集合查询集合(即,这里没有明确说明为什么会这样),那么您应该有两个。因为没有明显的需要将权限和用户分开,所以需要合并它们。如果权限用作令牌,请将它们分开。根据您提供的信息,没有迹象表明您需要两个独立的集合。SQL不是noSQL,反之亦然。假设我想插入一个新用户作为管理员。在应用程序方面,我是否应该查询角色集合以获取管理员的_id并将其放入新用户的角色字段中?驱动程序是服务器端的,除非您使用的是类似于Meteor的mini Mongo的东西;“应用程序端”有点模糊,太好了。如果我想添加一个角色为“admin”的用户,该怎么办?如何检查“admin”是否为有效角色?呃,对于您的第一个问题:这是对用户文档的简单更新。对于检查:
db.roles.find({u-id:admin},{u-id:1})
是不够的吗?这样可以,但是在插入之前需要对数据库进行另一次查询,对吗?然后导致两个网络延迟以完成插入操作。我们可以在数据库服务器上执行此检查吗?就像SQL的外键一样。或者我们可以在数据库上编写一些验证函数吗?@MatthewMa服务器端没有存储过程、触发器、连接和引用完整性。通常,这些只是将逻辑移动到它根本不属于的地方的东西:数据存储。将逻辑保持在它所属的位置,并且易于更新、管理和审查:代码。您可以将已知(读取:以前加载的)角色分配给用户。或者,如果用户得到一个无效的角色,则不会为该角色分配任何权限,因此不会造成任何伤害。有意义!谢谢!
var permission_needed = "adminService:*:*"

if(user_privileges.forAllRoles.indexOf(permission_needed) > -1){
  console.log("Yay, admin!");
  doSomeAdminStuff();
} else {
  console.log("Don't you dare again, user!");
}
db.roles.update(
  { _id: "roleName" },
  { $addToSet: { privileges: [ "otherService:*:someInstance" ] } }
)