我正在尝试使用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
}
它不起作用。可以在一个“查找”查询中执行此操作吗?
答案 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都不会自动管理外部引用。
替代解决方案:
所以,我看到的方法很少:
定义规则时检索所有车辆的ID。如果车辆数量不大(< = 1000)
,这种方法效果很好const vehicleIds = await getVehicleIds(user)
可以(['阅读','更新'],'文档',{vehicle:{$ in:vehicleIds}})
< / LI>反规范您的方案。例如,将额外的user_id
字段添加到车辆文档
想想你是否可以将文档作为子文档嵌入到vechicle中,如下所示:
车辆{ 文件:[文件], 用户:[{type:objectId,ref:&#39; user&#39;}] }不要为每个文档定义规则并在路由中强制执行(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}) })