Meteor Collection高级选择器

时间:2014-06-06 11:27:42

标签: meteor

我有一个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;
  }
});

会很好,有没有理由不存在?

2 个答案:

答案 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。

您提到的允许构造仅供我知道,仅用于更新和插入