2015-09-13 4 views
2

Предположим, у меня есть пользователи и роли. Каждый пользователь принадлежит к роли. Я хотел бы разработать базу данных, как это:Как проверить ссылку при вставке в MongoDB?

Коллекции Пользователей:

{ 
    "name":"user1" 
    "role":"admin" 
} 

Коллекция Роль:

{ 
    "name":"admin" 
    "privileges":[] 
} 
{ 
    "name":"user" 
    "privileges":[] 
} 

Позже я мог бы добавить больше ролей или редактирование привилегий для любой роли.

Мой вопрос: когда я вставляю нового пользователя, как я могу проверить, имеет ли поле «роль» допустимое значение (это означает, что в коллекции ролей есть документ соответствия)?

Должен ли я проверить эту ссылку в приложении? Есть ли способ сделать это на стороне сервера mongodb?

Предположим, что привилегия на редактирование является частой операцией.

+0

Если вам нужно, чтобы проверить это, запрос коллекции перед установкой пользователя. –

+0

@Michelem Это работает, но не эффективно. Это делается на стороне приложения. Для двух операций будут две задержки сети. Будет лучше, если мы сможем выполнить проверку на стороне сервера mongodb. –

ответ

1

Я думаю, что вы ставите телегу впереди лошади.

для моделирования данных, вы должны сначала что теперь ваши вопросы к данным есть. Что касается пользователей, ролей и привилегий связи, вопрос очевиден

Для данного пользователя, каковы привилегии?

Пока привилегии на роль не превышают несколько 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!"); 
} 

Поскольку мы LookUp привилегии по roles._id, который индексируется, агрегация должна быть довольно эффективно, потому что мы ограничиваем документы только очень немногими перед обработкой.

Если вы хотите добавить разрешение на роль, это просто

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

НТН

+0

это здорово. что, если я хочу добавить пользователя с ролью «admin»? как я могу проверить, является ли «админ» действительной ролью? –

+0

Erm, для вашего первого вопроса: это простое обновление для документа пользователя. Для проверки: 'db.roles.find ({_ id:" admin "}, {_ id: 1})' недостаточно? –

+0

Это работает, но перед вставкой требуется другой запрос к базе данных, правильно? Затем он вызывает две задержки сети, чтобы завершить операцию вставки. Можем ли мы выполнить эту проверку на сервере базы данных? Также как внешний ключ SQL. Или мы можем написать некоторые функции валидации в базе данных? –

1

Так как вы получите ваш индекс _id бесплатно, вы должны ссылаться на пользователя к роли _id

{ 
    _id: ObjectId("55f5128e6e5daa295293e31e"), 
    name: "admin" 
}, 
{ 
    _id: ObjectId("55f5128e6e5daa295293e31f"), 
    "name":"user" 
} 

и назначать привилегии для каждого пользователя

{ 
    "name":"user1", 
    "role":ObjectId("55f5128e6e5daa295293e31e"), 
    "privileges":[] 
} 

даже еще лучше, получить избавиться от коллекции ролей

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

или

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

EDIT:

Крис Ма «, что если у меня есть 1k пользователей с ролью„Администратор“, теперь я хочу, чтобы добавить привилегии для всех администраторов. Затем мне нужно отредактировать 1k пользователей. Правильно? У нас есть лучшее решение «

Если вы можете себе представить, решение было бы то же самое:

Коллекция„? Роли“

{ 
    _id: ObjectId("55f5128e6e5daa295293e31e"), 
    name: "admin", 
    my1KUpdate: "value" 
} 
+0

Что делать, если у меня есть 1k пользователей с ролью «admin», теперь я хочу добавить привилегию для всех администраторов. Затем мне нужно отредактировать 1k пользователей. Правильно? У нас есть лучшее решение? –

+0

Удаление коллекции ролей не кажется правильным. Как пользователь-админ (кто назначает привилегии) ​​мне нужен список доступных ролей на выбор. –

+0

Это зависит, однако, 9 из 10 раз, это правильная вещь. У вас есть 16 мб на документ, если вы думаете, что превысите его, а затем разделите их. Если вам нужно запросить сбор независимо друг от друга (т. Е. Здесь не указано, почему это должно быть так), тогда у вас должно быть два. Поскольку нет очевидной необходимости отделить разрешение от пользователя, консолидируйте их. Если разрешение служит токеном, держите их отдельно. Как и в случае с предоставленной вами информацией, нет никаких указаний на необходимость наличия двух независимых коллекций. SQL не является noSQL, и наоборот. – aug2uag

Смежные вопросы