猫鼬嵌套(2级)找到

时间:2018-05-03 11:42:26

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

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

我的域名是:

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

架构:

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // Initializing, etc.

        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mSectionsPagerAdapter);

        TabLayout tabLayout = findViewById(R.id.tabs);
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
    }

为了“按用户”找到车辆,我这样做:

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
}

它不起作用。可以在一个“查找”查询中执行此操作吗?

2 个答案:

答案 0 :(得分:0)

您无法在简单的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来过滤结果

答案 1 :(得分:0)

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

替代解决方案

所以,我看到的方法很少:

  1. 定义规则时检索所有车辆的ID。如果车辆数量不大(< = 1000)

    ,这种方法效果很好

    const vehicleIds = await getVehicleIds(user)

    可以(['阅读','更新'],'文档',{vehicle:{$ in:vehicleIds}})

    < / LI>
  2. 反规范您的方案。例如,将额外的user_id字段添加到车辆文档

  3. 想想你是否可以将文档作为子文档嵌入到vechicle中,如下所示:

    车辆{   文件:[文件],   用户:[{type:objectId,ref:&#39; user&#39;}] }

  4. 不要为每个文档定义规则并在路由中强制执行(REST或GraphQL并不重要)。

    app.get(&#39; / vehicle /:id / documents&#39;,async(req,res)=&gt; {    const vehicle = await Vehicle.findById(req.params.id)

    req.ability.throwUnlessCan(&#39; read&#39;,vehicle)    const documents = Document.find({vehicle:vehicle.id})

    res.send({documents}) })