MongoDB: Ссылка на другой документ с дополнительной информацией

У меня есть ситуация, когда у меня есть тип группового документа. Я хочу, чтобы поле со списком содержало ссылочный идентификатор для пользователей в группе. Однако мне нужно указать, какие пользователи имеют доступ администратора. Должен ли я иметь два списка, один из которых является обычным пользователем и одним из администраторов, или иметь собственный документ, в который я встраиваю список, в котором просто есть ссылочный идентификатор и значение bool? В основном это много ко многим, поскольку оба документа имеют список идентификаторов ссылок на другие документы. Я просто не уверен, как включить это другое значение.

Если это имеет какое-то значение, я использую Python/Mongoengine для доступа к MongoDB

1 ответ

Решение

Существуют различные способы моделирования вашего требования в текущей форме. Я попытаюсь показать вам один такой способ и использует $ lookup. Вы должны попробовать две отдельные коллекции, по одной для каждой группы и пользователей, как показано ниже.

Еще одним вариантом будет использование $DBRef, который будет загружать всех пользователей в группе, когда вы выбираете коллекцию группы. Эта опция будет зависеть от драйвера Python, и я уверен, что драйвер поддерживает это.

Документ группы

{
    "_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
    "name": "newGroup",
    "usersId": ["user1", "user2"]
}

Документ пользователя

{ "_id" : "user1", "isAdmin" : true }
{ "_id" : "user2" }

Получить всех пользователей в группе

db.groups.aggregate({
    $unwind: '$usersId'
}, {
    $lookup: {
        from: "users",
        localField: "usersId",
        foreignField: "_id",
        as: "group_users"
    }
})

отклик

{
    "_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
    "name": "newGroup",
    "usersId": "user1",
    "group_users": [{
        "_id": "user1",
        "isAdmin": true
    }]
} {
    "_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
    "name": "newGroup",
    "usersId": "user2",
    "group_users": [{
        "_id": "user2"
    }]
}

Получить всех администраторов в группе

db.groups.aggregate({
    $unwind: '$usersId'
}, {
    $lookup: {
        from: "users",
        localField: "usersId",
        foreignField: "_id",
        as: "group_users"
    }
}, {
    $match: {
        "group_users.isAdmin": {
            $exists: true
        }
    }
})

отклик

{
    "_id": ObjectId("5857e7d5aceaaa5d2254aea2"),
    "name": "newGroup",
    "usersId": "user1",
    "group_users": [{
        "_id": "user1",
        "isAdmin": true
    }]
}

На основании комментария:

Администратор является администратором для группы, поэтому я не могу сохранить его в таблице пользователей. Это отношения многие ко многим.

Я думаю, что вы должны включить как список обычных пользователей, так и список администраторов. Это будет использовать добавленные вами индексы и сделает ваши запросы на чтение действительно простыми.

Документ группы

{ "_id" : "newGroup", "userIds" : [ "user1" ], "adminIds" : [ "user2" ] }

Документ пользователя

{ "_id" : "user1", "groupIds" : [ "newGroup" ] } -- regular user in newGroup
{ "_id" : "user2", "groupIds" : [ "newGroup" ] } -- admin user in newGroup.
{ "_id" : "user3", "groupIds" : [ ] }

Получить всех постоянных пользователей

db.groups.aggregate({
    $unwind: '$userIds'
}, {
    $lookup: {
        from: "users",
        localField: "userIds",
        foreignField: "_id",
        as: "group_users"
    }
})

Получить всех администраторов

db.groups.aggregate({
    $unwind: '$adminIds'
}, {
    $lookup: {
        from: "users",
        localField: "adminIds",
        foreignField: "_id",
        as: "group_users"
    }
})
Другие вопросы по тегам