Мангуст гнездится (2 уровень) найти - PullRequest
0 голосов
/ 03 мая 2018

Я пытаюсь использовать CASL для проверки авторизации вложенных элементов. Он использует мангуста для запроса данных и проверки доступа.

Мой домен таков:

  • «Пользователь» может иметь больше «Транспортных средств»
  • «Документ» должен иметь транспортное средство

Схема:

vehicle { users: [ {type: objectId, ref: 'user'} ] }
document { vehicle: {type: objectId, ref: 'vehicle' }}

Чтобы найти транспортное средство "по пользователю", я делаю:

db.getCollection('vehicle').find(
    { users: {$in: [ ObjectId("5ae1a957d67500018efa2c9d") ]} }
)

Это работает.

В коллекции документов есть такие записи:

{
    "_id": ObjectId("5aeaad1277e8a6009842564d"),
    "vehicle": ObjectId("5aea338b82d8170096b52ce9"),
    "company": "Allianz",
    "price": 500,
    "date_start": ISODate("2018-05-02T22:00:00.000Z"),
    "date_end": ISODate("2019-05-02T22:00:00.000Z"),
    "createdAt": ISODate("2018-05-03T06:32:50.590Z"),
    "updatedAt": ISODate("2018-05-03T06:32:50.590Z"),
    "__v": 0
}

Чтобы найти документ «по пользователю», я делаю:

db.getCollection('document').find(
    { "vehicle.users": {$in: [ ObjectId("5ae1a957d67500018efa2c9d") ]} }
)

Это не работает. Можно ли сделать это в одном запросе "find"?

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Для того, чтобы этот запрос работал, вам нужно сохранить массив users ids в документе vehicle. Ни Mongo, ни CASL не управляют внешними ссылками автоматически.

Альтернативные решения :

Итак, я вижу несколько способов:

  1. Получить идентификаторы всех транспортных средств, когда вы определяете правила. Это хорошо работает, если количество транспортных средств невелико (<= 1000) </p>

    const vehicleIds = await getVehicleIds (пользователь)

    can (['read', 'update'], 'document', {vehicle: {$ in: vehicleIds}})

  2. Денормализуйте вашу схему. Например, добавьте дополнительное поле user_id к документу транспортного средства

  3. Подумайте, можете ли вы встроить документ как вложенный документ в vechicle, что-то вроде этого:

    транспортное средство { документы: [Документ], пользователи: [{type: objectId, ref: 'user'}] }

  4. Просто не определяйте правила для документов и применяйте их в маршрутах (REST или GraphQL не имеет значения).

    app.get ('/ vehicle /: id / documents', async (req, res) => { const vehicle = await Vehicle.findById (req.params.id)

    req.ability.throwUnlessCan ('read', vehicle) постоянные документы = Document.find ({vehicle: vehicle.id})

    res.send ({документы}) })

0 голосов
/ 03 мая 2018

Вы не можете сделать это простым запросом MongoDB find () , потому что данные о пользователях транспортных средств существуют в коллекции транспортных средств, а не в коллекции документов.

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

db.document.aggregate([
  {$lookup: {
    "from": "vehicle",
    "localField": "vehicle",
    "foreignField": "_id",
    "as": "vehicleDetails",
  }},
  {$match: {"vehicleDetails.users" : ObjectId("5ae1a957d67500018efa2c9d")}}
])

Возможно, вам потребуется добавить дополнительные этапы для изменения формы данных так, как вам это нужно, но ключом является использование $ lookup для связи данных из двух коллекций, а затем использование $ match для фильтрации множество результатов.

...