我有一个Project集合和一个Task集合。
每个项目都有一个user_id字段,它保存项目的所有者。
每个任务都有一个project_id字段。所以结构是这样的:
- 用户1
- 项目1
- 任务1
- 任务2
- 项目2
- 任务3
- 用户2
- 项目3
- 任务4
- 任务5
出于安全考虑,我只想发布属于某个登录用户的项目。对于项目本身而言非常简单:
Meteor.publish('projects', function(){
return Projects.find({user_id: this.userId});
});
但是,如何以干净的方式为Task集合执行此操作?为什么Collection.Allow没有'view'选项?
类似的东西:
Tasks.allow({
view: function (userId, doc) {
return Projects.findOne(doc.project_id).user_id == userId;
}
});
会很好,有没有理由不存在?
答案 0 :(得分:4)
首先,一些推荐阅读:
加入流星目前很棘手。在发布功能中加入集合很容易,但要使它们具有反应性(在事情发生变化时再次运行)并不总是直截了当。
您可以使用以下方式同时发布这两个集合:
Meteor.publish('projectsAndTasks', function() {
var projectsCursor = Projects.find({user_id: this.userId});
var projectIds = projectsCursor.map(function(p) { return p._id });
return [
projectsCursor,
Tasks.find({project_id: {$in: projectIds}});
];
});
潜在的问题是,如果将任务添加到新项目中,它们将不会被发布(参见上面第一篇文章中的"朴素方法")。根据应用程序的启动和停止订阅的方式,这可能无关紧要。如果您发现它,请继续阅读。
一个简单的选择就是对数据进行非规范化。如果您还在任务中添加了user_id
,则无需加入,发布函数如下所示:
Meteor.publish('projectsAndTasks', function() {
var projectsCursor = Projects.find({user_id: this.userId});
var tasksCursor = Tasks.find({user_id: this.userId});
return [projectsCursor, tasksCursor];
});
如果这并不适合您,并且您使用的是铁路由器,则可以在路由中进行客户端加入(请参阅"加入客户端"来自上面的第一篇文章)。它有点慢,因为你需要第二次往返,但它很干净,因为不需要修改数据,也不需要添加外部包。
最后,您可以在服务器上执行反应式连接,可以手动使用observeChanges(不推荐),也可以使用包。我过去曾使用publish-with-relations,但它有一些问题,如文章中所指出的那样)。有关包选项的更完整列表,您可以看到this thread。
不是流星的核心开发者,我不能准确回答为什么允许/拒绝没有"阅读"选项,但我会采取有根据的猜测。根据允许/拒绝功能的编写方式,发布者可能必须为每个单个文档或部分更新运行昂贵的回调。在修改单个文档时容易容忍允许/拒绝回调,但如果您突然需要发布数百个文档,并且每个文档在传输之前需要单独评估,我不认为这是实用的。我非常确定这是为什么发布商可以单独作为文档读取授权的仲裁者。
答案 1 :(得分:1)
您可以为任务执行此操作:
Meteor.publish('tasks', function(){
var projects = Projects.find({user_id: this.userId}, {fields: {_id: 1}});
var projectIdList = projects.map(function(project) { return project._id;});
return Tasks.find({project_id: {$in: projectIdList}});
});
首先,我们获得属于该用户的所有项目。我们只需要_id字段,所以我们过滤其他字段
然后我们将项目的_id映射到一个新数组。
然后我们发布一个tasks.find,其中包含映射数组中的所有项目ID。
您提到的允许构造仅供我知道,仅用于更新和插入