【问题标题】:Meteor Collection advanced selectorMeteor Collection 高级选择器
【发布时间】:2014-06-06 11:27:42
【问题描述】:

我有一个项目集合和一个任务集合。

每个项目都有一个 user_id 字段,其中包含项目的所有者。

每个任务都有一个 project_id 字段。所以结构是这样的:

  • 用户 1
    • 项目一
    • 任务 1
    • 任务 2
    • 项目 2
    • 任务 3
  • 用户 2
    • 项目 3
    • 任务 4
    • 任务 5

出于安全考虑,我只想发布属于某个登录用户的项目。对于项目本身来说,这很容易:

Meteor.publish('projects', function(){
    return Projects.find({user_id: this.userId});
});

但是我如何以干净的方式为任务集合做到这一点?为什么 Collection.Allow 没有“查看”选项?

类似:

Tasks.allow({
  view: function (userId, doc) {
    return Projects.findOne(doc.project_id).user_id == userId;
  }
});

会很好,它不存在有什么原因吗?

【问题讨论】:

    标签: meteor


    【解决方案1】:

    首先,一些推荐阅读:

    流星中的连接目前很棘手。在发布函数中加入集合很容易,但让它们成为响应式(当事情发生变化时再次运行)并不总是那么简单。

    非反应性选项

    您可以同时发布两个集合:

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

    如果这对您没有吸引力并且您正在使用 Iron-router,您可以在您的路由中进行客户端连接(请参阅上面第一篇文章中的“在客户端连接”)。它有点慢,因为您需要第二次往返,但它很干净,不需要修改数据,也不需要添加外部包。

    最后,您可以使用observeChanges(不推荐)手动或使用包在服务器上进行反应式连接。我过去使用过publish-with-relations,但它有一些文章中指出的问题)。如需更完整的软件包选项列表,您可以查看this thread


    不是流星的核心开发人员,对于为什么允许/拒绝没有“读取”选项,我没有确切的答案,但我会做出有根据的猜测。根据允许/拒绝函数的编写方式,发布者可能必须为每个文档或部分更新运行昂贵的回调。当修改单个文档时,允许/拒绝回调很容易容忍,但是如果您突然需要发布数百个文档并且每个文档都需要在传输之前单独评估,我认为这不切实际。我很确定这就是为什么出版商可以单独充当文档读取授权的仲裁者。

    【讨论】:

    • 我可以使用https://github.com/matb33/meteor-collection-hooksproject.after.insert 服务器端调用您的第一个示例中的方法吗?这有意义吗?还是需要来自客户的新请求?
    • 如果您指的是非规范化选项,是的,collection-hooks 会起作用。或者,您可以添加 user_idthis hack
    【解决方案2】:

    您可以为任务执行此操作:

    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。

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

    【讨论】:

    • 请注意,如果用户的项目发生变化,这将不起作用。如果用户创建了一个新项目,他们将无法获得该项目中的任务,除非他们取消订阅并重新订阅。或者,如果项目更改了所有者,他们仍将获得该项目的任务(直到他们重新订阅)。服务器上没有Deps 响应,当Projects.find({user_id: this.userId}, {fields: {_id: 1}}) 更改时,发布功能不会重新运行。
    猜你喜欢
    • 2010-10-26
    • 1970-01-01
    • 2015-03-07
    • 2011-07-28
    • 2010-11-16
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    • 2011-11-01
    相关资源
    最近更新 更多