MongoDB : 如何设计基于应用程序访问模式的架构?
MongoDB : How to design schema based on application access patterns?
作为来自 DynamoDB 的人,对 MongoDB 架构进行建模以真正深入地融入我的应用程序有点令人困惑,特别是因为它具有引用的概念,而且根据我的阅读,不建议保留重复的内容数据来满足您的查询。
以下面的例子为例(在 mongoengine 中建模,但应该无关紧要):
#User
class User(Document):
email = EmailFieldprimary_key=True)
pswd_hash = StringField()
#This also makes it easier to find the Projects the user has a Role
roles = ListField(ReferenceField('Role')
#Project
class Project(Document):
name = StringField()
#This is probably unnecessary as the Role id is already the project id
roles = ListField(ReferenceField('Role'))
#Roles in project
class Role(Document):
project = ReferenceField('Project', primary_key=True)
#List of permissions
permissions = ListField(StringField())
users = ListField(ReferenceField('User')
有项目和用户。
每个项目可以有很多角色。
每个用户在项目.
中可以有一个角色
所以,它是 Users 和 Projects
之间的多对多
用户和角色
之间的多对一
角色和项目
之间的多对一关系
问题是当我尝试将架构适应访问时,因为在应用程序的每个页面刷新时,我需要:
- 项目(id在url)
- 用户(电子邮件正在会话中)
- 该项目中的用户权限(服务器端安全检查)
因此,考虑到这是最常见的查询,我应该如何为我的架构建模以适应它?
或者我现在的做法已经可以了吗?
有不同的建模方法,对于这个特定的用例,我建议将 roles/permissions 嵌套在项目文档中。
事实上,据我了解,您的角色不会在项目之间共享,因此有机会嵌入它,以及 project-roles 和用户之间的映射。这是我的建议(使用简化的类):
class User(Document):
name = StringField()
class RoleDefinition(EmbeddedDocument):
users = ListField(ReferenceField(User))
permissions = ListField(StringField())
class Project(Document):
role_definitions = EmbeddedDocumentListField(RoleDefinition)
def has_user_permission(self, user_id, permission):
for role_def in self.role_definitions:
if permission in role_def.permissions:
return user_id in [us.id for us in role_def._data['users']] # optimization to avoid to dereference all the users
return False
# save a sample
bob = User(name='Bob').save()
hulk = User(name='hulk').save()
project = Project(
role_definitions=[
RoleDefinition(permissions=['read_file', 'delete_file'], users=[bob]),
RoleDefinition(permissions=['upload_file'], users=[hulk])
]
).save()
# Check if a user has a certain permission in a project
assert project.has_user_permission(bob.id, 'read_file') is True
这将保存具有以下结构的文档:
{
'_id':ObjectId('5d2cd78cd97f1cc85d0b7b28'),
'role_definitions':[
{
'permissions':['read_file', 'delete_file'],
'users':[ObjectId('5d2cd5d6d97f1cc85d0b7b26')]
},
{
'permissions':['upload_file'],
'users':[ObjectId('5d2cd5d9d97f1cc85d0b7b27')]
}
]
}
然后您可以通过以下查询验证具有特定 ID 的用户是否在项目中具有特定权限:
def user_has_permission_in_project(project_id, user_id, permission):
qry = Project.objects(id=project_id,
role_definitions__elemMatch={'users': user_id, 'permissions': permission})
return qry.count() > 0
assert user_has_permission_in_project(project.id, bob.id, 'read_file') is True
假设它符合您的限制,您应该能够根据您的需要进行调整
有多种方法可以在当前表单中对您的需求进行建模。
如果您没有太多重复并且在请求文档时总是需要嵌入数据,则可以使用嵌入文档。
在你的情况下,我会使用引用。你的整体结构我觉得不错。
我将尝试向您展示一种这样的方式和用法 $lookup
with references
。您应该尝试使用三个单独的集合,每个项目、角色和用户一个,如下所示。
另一种选择是使用 $DBRef
,它会在您获取项目集合时预先加载项目中的所有角色。此选项将取决于 mongoengine 驱动程序,我确定驱动程序支持它。
项目文档(已从项目中删除角色)
{ "_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
"name": "newProject"
}
角色文件
{ "_id" : "role1",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"users": ["email1", "email2"],
"permissions": ["delete","update"]
}
{ "_id" : "role2",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"users": ["email1"],
"permissions": ["add"]
}
用户文档
{ "email" : "email1",
"roles": ["role1", "role2"]
}
{ "email" : "email2",
"roles": ["role1"]
}
显示所有项目
db.project.find({})
获取项目中的所有角色
db.role.aggregate([
{$match: {project:ObjectId("5857e7d5aceaaa5d2254aea2")} },
])
回应
{
"_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
"name": "newProject",
"roles": [
{ "_id" : "role1",
"users": ["email1", "email2"]
},
{ "_id" : "role2",
"users": ["email1"]
}
]
}
获取用户的所有角色
db.user.aggregate([
{$match: {email:"email1"}},
{$lookup: {
from: "role",
localField: "roles",
foreignField: "_id",
as: "roles"
}}
])
回应
{
"email": "email1",
"roles": [
{ "_id" : "role1",
"users": ["email1", "email2"]
},
{ "_id" : "role2",
"users": ["email1"]
}
]
}
获取项目 ID 和电子邮件 ID 的用户权限(使用当前结构)
db.role.aggregate([
{$match: {_id:ObjectId("5857e7d5aceaaa5d2254aea2")}},
{$match: {"$expr": {"$in": ["email1", "$users"]}}},
{$project:{"permissions":1}}
])
回应
[
{
"permissions": ["delete","add"]
},
{
"permissions": ["update"]
}
]
随着用户的不断增加,您可以从角色集合中删除用户,并且可以使用 $lookup 将用户加入角色集合以识别项目。像
角色文档(已从角色中删除用户)
{ "_id" : "role1",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"permissions": ["delete","update"]
}
{ "_id" : "role2",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"permissions": ["add"]
}
用户文档
{ "email" : "email1",
"roles": ["role1", "role2"]
}
{ "email" : "email2",
"roles": ["role1"]
}
获取项目 ID 和电子邮件 ID 的用户权限(更新结构)(首选)
db.user.aggregate([
{$match: {email:"email1"}},
{$lookup: {
from: "role",
localField: "roles",
foreignField: "_id",
as: "roles"
}},
{$unwind: "$roles"},
{$match: {"roles.project": ObjectId("5857e7d5aceaaa5d2254aea2")}},
{$project:{"permissions":"$roles.permissions"}}
])
回应
[
{
"permissions": ["delete","update"]
},
{
"permissions": ["add"]
}
]
通常,您可以通过两种方式对权限进行建模。或者,有静态角色,它们具有执行某些事情的隐式权限。或者有些角色只是显式权限的容器。
隐式权限
文档的大小限制为 16MB,因此除非您有 lot 的用户和 lot 的角色,否则规范化是没必要。
{
"_id": new ObjectID(),
"name": "My Project",
"roles": [
{
"role": "admin",
"members": ["foo","bar"]
},
{
"role": "user",
"members": ["baz","foo"]
}
]
}
这里有一个简单数据模型的另一种方法是每个关系有一个文档:
{"project":someObjectId,"role":"admin","user":"foo"}
{"project":someObjectId,"role":"admin","user":"bar"}
{"project":someObjectId,"role":"user","user":"baz"}
现在,您大概了解您的项目,因此您可以像查询特定用户的角色一样简单:
db.roles.find({"project":currentProjectId,"user":currentUser})
如果一个用户可以有多个角色,您可以进行聚合,例如:
// Add to above data
// db.roles.insert({"project":ObjectId("5d2f6f0fd2c6b42117ecbbe5"),role:"user",user:"foo"})
db.roles.aggregate([{
$match:{
user:"foo",
project:ObjectId("5d2f6f0fd2c6b42117ecbbe5")
}},{
$group:{
"_id":"$user",
roles:{$addToSet:"$role"}
}}
])
// Result
{ "_id" : "foo", "roles" : [ "user", "admin" ] }
使用 user
和 project
上的复合索引(顺序很重要!),此聚合查询应该是最足够的。
显式权限
首先,我们必须定义要如何设置显式权限。一种可靠的方法是使用
domain:action[,action...]:instance
(公然取自 Apache Shiro's permission model)。在不知道您希望通过应用程序实现什么的情况下很难对其进行建模,但是为了举例,我们假设具有更改任何项目标题的权限。所以抽象描述将是:
project:editTitle:*
如果您不需要实例级权限,那就更简单了:
project:editTitle
这很容易解析,角色可以定义为
{
"_id":"editor",
"permissions":[
"project:editTitle",
"project:addUser",
"project:stop",
"project:andSoOnAndSoForth",
"comment:dlete"
]
}
嘿,等等,打错字了!让我们更正一下:
db.permissions.update(
{permissions:"comment:dlete"},
{$set:{"permissions.$":"comment:delete"}}
)
(如果你也想改写权限,这很方便——只是不要忘记添加 {multi:true}
作为第三个参数)。
现在赋予角色
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "admin", "user" : "foo" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "admin", "user" : "bar" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "user", "user" : "baz" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "user", "user" : "foo" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "editor", "user" : "baz" }
和类似
的权限
{ "_id" : "editor", "permissions" : [ "project:editTitle", "project:addUser", "project:stop", "project:andSoOnAndSoForth", "comment:delete" ] }
{ "_id" : "user", "permissions" : [ "*:read" ] }
{ "_id" : "admin", "permissions" : [ "*:*" ] }
您可以通过
获得用户对项目的显式权限
db.roles.aggregate([
// we only want to get the roles of the current user for a certain project
{ $match: { user: "baz", project: ObjectId("5d2f6f0fd2c6b42117ecbbe5") } },
// We get the permissions associated with the role
{ $lookup: { from: "permissions", localField: "role", foreignField: "_id", as: "permissionDocs" } },
// We pull the permissions into the root document...
{ $replaceRoot: { newRoot: { $mergeObjects: [{ $arrayElemAt: ["$permissionDocs", 0] }, "$$ROOT"] } } },
// ... and get rid of all the stuff we do not need
{ $project: { permissionDocs: 0, role: 0, project: 0 } },
// We flatten the various permission arrays of the result documents...
{ $unwind: "$permissions" },
// ... and finally construct our set of permissions
{ $group: { "_id": "$user", permissions: { $addToSet: "$permissions" } } }
])
// Result:
{ "_id" : "baz", "permissions" : [ "comment:delete", "project:andSoOnAndSoForth", "*:read", "project:editTitle", "project:addUser", "project:stop" ] }
有了这个结果,您可以简单地遍历权限集并允许删除评论,例如,如果权限 *:*
、comment:*
或 comment:delete
存在。
请注意,我没有规范化角色的权限。这为我们节省了对非常常见的用例的额外查找,但代价是相当罕见的用例(更改权限域或操作)速度较慢。
编辑:
您可以将其包装成一个函数,例如:
function hasPermission(user, project, permission) {
var has = db.roles.aggregate([{
$match: {
user: user,
project: project
}}, {
$lookup: {
from: "permissions",
localField: "role",
foreignField: "_id",
as: "permissionDocs"
}}, {
$replaceRoot: {
newRoot: {
$mergeObjects: [{
$arrayElemAt: ["$permissionDocs", 0]
}, "$$ROOT"]
}
}}, {
$project: {
permissionDocs: 0,
role: 0,
project: 0
}}, {
$unwind: "$permissions"
}, {
$group: {
"_id": "$user",
permissions: {
$addToSet: "$permissions"
}
}
}, {
$match: {
"permissions": permission
}
}]);
return has.toArray().length > 0
}
所以像这样:
> if ( hasPermission("baz",ObjectId("5d2f6f0fd2c6b42117ecbbe5"),"comment:delete") ) {
print("Jay")
} else {
print("Nay")
}
结果 Yay
。 (请注意,您需要扩展函数以匹配通配符权限 comment:*
和 *:*
。)
作为来自 DynamoDB 的人,对 MongoDB 架构进行建模以真正深入地融入我的应用程序有点令人困惑,特别是因为它具有引用的概念,而且根据我的阅读,不建议保留重复的内容数据来满足您的查询。
以下面的例子为例(在 mongoengine 中建模,但应该无关紧要):
#User
class User(Document):
email = EmailFieldprimary_key=True)
pswd_hash = StringField()
#This also makes it easier to find the Projects the user has a Role
roles = ListField(ReferenceField('Role')
#Project
class Project(Document):
name = StringField()
#This is probably unnecessary as the Role id is already the project id
roles = ListField(ReferenceField('Role'))
#Roles in project
class Role(Document):
project = ReferenceField('Project', primary_key=True)
#List of permissions
permissions = ListField(StringField())
users = ListField(ReferenceField('User')
有项目和用户。
每个项目可以有很多角色。
每个用户在项目.
中可以有一个角色所以,它是 Users 和 Projects
之间的多对多用户和角色
之间的多对一角色和项目
之间的多对一关系问题是当我尝试将架构适应访问时,因为在应用程序的每个页面刷新时,我需要:
- 项目(id在url)
- 用户(电子邮件正在会话中)
- 该项目中的用户权限(服务器端安全检查)
因此,考虑到这是最常见的查询,我应该如何为我的架构建模以适应它?
或者我现在的做法已经可以了吗?
有不同的建模方法,对于这个特定的用例,我建议将 roles/permissions 嵌套在项目文档中。
事实上,据我了解,您的角色不会在项目之间共享,因此有机会嵌入它,以及 project-roles 和用户之间的映射。这是我的建议(使用简化的类):
class User(Document):
name = StringField()
class RoleDefinition(EmbeddedDocument):
users = ListField(ReferenceField(User))
permissions = ListField(StringField())
class Project(Document):
role_definitions = EmbeddedDocumentListField(RoleDefinition)
def has_user_permission(self, user_id, permission):
for role_def in self.role_definitions:
if permission in role_def.permissions:
return user_id in [us.id for us in role_def._data['users']] # optimization to avoid to dereference all the users
return False
# save a sample
bob = User(name='Bob').save()
hulk = User(name='hulk').save()
project = Project(
role_definitions=[
RoleDefinition(permissions=['read_file', 'delete_file'], users=[bob]),
RoleDefinition(permissions=['upload_file'], users=[hulk])
]
).save()
# Check if a user has a certain permission in a project
assert project.has_user_permission(bob.id, 'read_file') is True
这将保存具有以下结构的文档:
{
'_id':ObjectId('5d2cd78cd97f1cc85d0b7b28'),
'role_definitions':[
{
'permissions':['read_file', 'delete_file'],
'users':[ObjectId('5d2cd5d6d97f1cc85d0b7b26')]
},
{
'permissions':['upload_file'],
'users':[ObjectId('5d2cd5d9d97f1cc85d0b7b27')]
}
]
}
然后您可以通过以下查询验证具有特定 ID 的用户是否在项目中具有特定权限:
def user_has_permission_in_project(project_id, user_id, permission):
qry = Project.objects(id=project_id,
role_definitions__elemMatch={'users': user_id, 'permissions': permission})
return qry.count() > 0
assert user_has_permission_in_project(project.id, bob.id, 'read_file') is True
假设它符合您的限制,您应该能够根据您的需要进行调整
有多种方法可以在当前表单中对您的需求进行建模。
如果您没有太多重复并且在请求文档时总是需要嵌入数据,则可以使用嵌入文档。
在你的情况下,我会使用引用。你的整体结构我觉得不错。
我将尝试向您展示一种这样的方式和用法 $lookup
with references
。您应该尝试使用三个单独的集合,每个项目、角色和用户一个,如下所示。
另一种选择是使用 $DBRef
,它会在您获取项目集合时预先加载项目中的所有角色。此选项将取决于 mongoengine 驱动程序,我确定驱动程序支持它。
项目文档(已从项目中删除角色)
{ "_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
"name": "newProject"
}
角色文件
{ "_id" : "role1",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"users": ["email1", "email2"],
"permissions": ["delete","update"]
}
{ "_id" : "role2",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"users": ["email1"],
"permissions": ["add"]
}
用户文档
{ "email" : "email1",
"roles": ["role1", "role2"]
}
{ "email" : "email2",
"roles": ["role1"]
}
显示所有项目
db.project.find({})
获取项目中的所有角色
db.role.aggregate([
{$match: {project:ObjectId("5857e7d5aceaaa5d2254aea2")} },
])
回应
{
"_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
"name": "newProject",
"roles": [
{ "_id" : "role1",
"users": ["email1", "email2"]
},
{ "_id" : "role2",
"users": ["email1"]
}
]
}
获取用户的所有角色
db.user.aggregate([
{$match: {email:"email1"}},
{$lookup: {
from: "role",
localField: "roles",
foreignField: "_id",
as: "roles"
}}
])
回应
{
"email": "email1",
"roles": [
{ "_id" : "role1",
"users": ["email1", "email2"]
},
{ "_id" : "role2",
"users": ["email1"]
}
]
}
获取项目 ID 和电子邮件 ID 的用户权限(使用当前结构)
db.role.aggregate([
{$match: {_id:ObjectId("5857e7d5aceaaa5d2254aea2")}},
{$match: {"$expr": {"$in": ["email1", "$users"]}}},
{$project:{"permissions":1}}
])
回应
[
{
"permissions": ["delete","add"]
},
{
"permissions": ["update"]
}
]
随着用户的不断增加,您可以从角色集合中删除用户,并且可以使用 $lookup 将用户加入角色集合以识别项目。像
角色文档(已从角色中删除用户)
{ "_id" : "role1",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"permissions": ["delete","update"]
}
{ "_id" : "role2",
"project": ObjectId("5857e7d5aceaaa5d2254aea2");
"permissions": ["add"]
}
用户文档
{ "email" : "email1",
"roles": ["role1", "role2"]
}
{ "email" : "email2",
"roles": ["role1"]
}
获取项目 ID 和电子邮件 ID 的用户权限(更新结构)(首选)
db.user.aggregate([
{$match: {email:"email1"}},
{$lookup: {
from: "role",
localField: "roles",
foreignField: "_id",
as: "roles"
}},
{$unwind: "$roles"},
{$match: {"roles.project": ObjectId("5857e7d5aceaaa5d2254aea2")}},
{$project:{"permissions":"$roles.permissions"}}
])
回应
[
{
"permissions": ["delete","update"]
},
{
"permissions": ["add"]
}
]
通常,您可以通过两种方式对权限进行建模。或者,有静态角色,它们具有执行某些事情的隐式权限。或者有些角色只是显式权限的容器。
隐式权限
文档的大小限制为 16MB,因此除非您有 lot 的用户和 lot 的角色,否则规范化是没必要。
{
"_id": new ObjectID(),
"name": "My Project",
"roles": [
{
"role": "admin",
"members": ["foo","bar"]
},
{
"role": "user",
"members": ["baz","foo"]
}
]
}
这里有一个简单数据模型的另一种方法是每个关系有一个文档:
{"project":someObjectId,"role":"admin","user":"foo"}
{"project":someObjectId,"role":"admin","user":"bar"}
{"project":someObjectId,"role":"user","user":"baz"}
现在,您大概了解您的项目,因此您可以像查询特定用户的角色一样简单:
db.roles.find({"project":currentProjectId,"user":currentUser})
如果一个用户可以有多个角色,您可以进行聚合,例如:
// Add to above data
// db.roles.insert({"project":ObjectId("5d2f6f0fd2c6b42117ecbbe5"),role:"user",user:"foo"})
db.roles.aggregate([{
$match:{
user:"foo",
project:ObjectId("5d2f6f0fd2c6b42117ecbbe5")
}},{
$group:{
"_id":"$user",
roles:{$addToSet:"$role"}
}}
])
// Result
{ "_id" : "foo", "roles" : [ "user", "admin" ] }
使用 user
和 project
上的复合索引(顺序很重要!),此聚合查询应该是最足够的。
显式权限
首先,我们必须定义要如何设置显式权限。一种可靠的方法是使用
domain:action[,action...]:instance
(公然取自 Apache Shiro's permission model)。在不知道您希望通过应用程序实现什么的情况下很难对其进行建模,但是为了举例,我们假设具有更改任何项目标题的权限。所以抽象描述将是:
project:editTitle:*
如果您不需要实例级权限,那就更简单了:
project:editTitle
这很容易解析,角色可以定义为
{
"_id":"editor",
"permissions":[
"project:editTitle",
"project:addUser",
"project:stop",
"project:andSoOnAndSoForth",
"comment:dlete"
]
}
嘿,等等,打错字了!让我们更正一下:
db.permissions.update(
{permissions:"comment:dlete"},
{$set:{"permissions.$":"comment:delete"}}
)
(如果你也想改写权限,这很方便——只是不要忘记添加 {multi:true}
作为第三个参数)。
现在赋予角色
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "admin", "user" : "foo" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "admin", "user" : "bar" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "user", "user" : "baz" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "user", "user" : "foo" }
{ "project" : ObjectId("5d2f6f0fd2c6b42117ecbbe5"), "role" : "editor", "user" : "baz" }
和类似
的权限{ "_id" : "editor", "permissions" : [ "project:editTitle", "project:addUser", "project:stop", "project:andSoOnAndSoForth", "comment:delete" ] }
{ "_id" : "user", "permissions" : [ "*:read" ] }
{ "_id" : "admin", "permissions" : [ "*:*" ] }
您可以通过
获得用户对项目的显式权限db.roles.aggregate([
// we only want to get the roles of the current user for a certain project
{ $match: { user: "baz", project: ObjectId("5d2f6f0fd2c6b42117ecbbe5") } },
// We get the permissions associated with the role
{ $lookup: { from: "permissions", localField: "role", foreignField: "_id", as: "permissionDocs" } },
// We pull the permissions into the root document...
{ $replaceRoot: { newRoot: { $mergeObjects: [{ $arrayElemAt: ["$permissionDocs", 0] }, "$$ROOT"] } } },
// ... and get rid of all the stuff we do not need
{ $project: { permissionDocs: 0, role: 0, project: 0 } },
// We flatten the various permission arrays of the result documents...
{ $unwind: "$permissions" },
// ... and finally construct our set of permissions
{ $group: { "_id": "$user", permissions: { $addToSet: "$permissions" } } }
])
// Result:
{ "_id" : "baz", "permissions" : [ "comment:delete", "project:andSoOnAndSoForth", "*:read", "project:editTitle", "project:addUser", "project:stop" ] }
有了这个结果,您可以简单地遍历权限集并允许删除评论,例如,如果权限 *:*
、comment:*
或 comment:delete
存在。
请注意,我没有规范化角色的权限。这为我们节省了对非常常见的用例的额外查找,但代价是相当罕见的用例(更改权限域或操作)速度较慢。
编辑:
您可以将其包装成一个函数,例如:
function hasPermission(user, project, permission) {
var has = db.roles.aggregate([{
$match: {
user: user,
project: project
}}, {
$lookup: {
from: "permissions",
localField: "role",
foreignField: "_id",
as: "permissionDocs"
}}, {
$replaceRoot: {
newRoot: {
$mergeObjects: [{
$arrayElemAt: ["$permissionDocs", 0]
}, "$$ROOT"]
}
}}, {
$project: {
permissionDocs: 0,
role: 0,
project: 0
}}, {
$unwind: "$permissions"
}, {
$group: {
"_id": "$user",
permissions: {
$addToSet: "$permissions"
}
}
}, {
$match: {
"permissions": permission
}
}]);
return has.toArray().length > 0
}
所以像这样:
> if ( hasPermission("baz",ObjectId("5d2f6f0fd2c6b42117ecbbe5"),"comment:delete") ) {
print("Jay")
} else {
print("Nay")
}
结果 Yay
。 (请注意,您需要扩展函数以匹配通配符权限 comment:*
和 *:*
。)