0

我正在尝试使用 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") ]} }
)

它不起作用。是否可以在一个“查找”查询中做到这一点?

4

2 回答 2

1

为了让这个查询工作,你需要将usersids 数组存储在vehicle文档中。Mongo 和 CASL 都不会自动管理外部引用。

替代解决方案

所以,我看到了几种方法:

  1. 定义规则时检索所有车辆的 ID。如果车辆数量不大(<= 1000),这很有效
const vehicleIds = await getVehicleIds(user)

can(['read', 'update'], 'document', { vehicle: { $in: vehicleIds } })
  1. 非规范化您的方案。例如,user_id向车辆文档添加附加字段
  2. 考虑一下是否可以将文档作为子文档嵌入到车辆中,如下所示:
vehicle {
  documents: [Document],
  users: [ {type: objectId, ref: 'user'} ]
}
  1. 只是不要为每个文档定义规则并在路由中强制执行它们(REST 或 GraphQL 无关紧要)。
app.get('/vehicle/:id/documents', async (req, res) => {
  const vehicle = await Vehicle.findById(req.params.id)

  req.ability.throwUnlessCan('read', vehicle)
  const documents = Document.find({ vehicle: vehicle.id })

  res.send({ documents })
})
于 2018-06-05T10:52:44.003 回答
1

您无法在简单的 MongoDB find() 查询中执行此操作,因为有关车辆用户的数据存在于车辆集合中,而不是文档集合中。

但是,聚合管道可以使用$lookup运算符链接两个不同集合中的数据。聚合将是这样的:

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

您可能需要添加更多阶段以按照您需要的方式重塑数据,但关键是使用 $lookup 链接来自两个集合的数据,然后使用$match过滤结果集。

于 2018-05-03T18:18:41.900 回答