【问题标题】:Mongoose nested (2 level) findMongoose 嵌套(2 级)查找
【发布时间】:2018-05-03 11:42:25
【问题描述】:

我正在尝试使用 CASL 对嵌套项进行授权检查。 它使用 mongoose 查询数据并检查访问权限。

我的域名是:

  • “用户”可以拥有更多“车辆”
  • “文件”必须有车辆

架构:

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") ]} }
)

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

【问题讨论】:

  • 嗨阿德里亚诺;您可以在第二个查询中仔细检查集合名称吗?你说你想查询documents,但它又说getCollection('vehicles')。您似乎不小心查询了错误的集合。
  • 是的,抱歉,我修复了我的帖子正文。我正在查询 0 个结果的文档。
  • 好的,这已经澄清了。我还有一个问题:您能否粘贴一个文档记录的示例,应该由您的查询返回?
  • { "_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 }

标签: node.js mongodb mongoose mongoose-schema casl


【解决方案1】:

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

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

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

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

【讨论】:

【解决方案2】:

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

替代解决方案

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

  1. 在定义规则时检索所有车辆的 ID。如果车辆数量不大(,这很有效
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 })
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    • 2012-05-26
    • 2022-09-29
    • 2019-09-18
    • 2020-07-16
    • 2018-09-10
    • 2021-02-21
    相关资源
    最近更新 更多