如何使用meteor发布/订阅正确过滤数据,这样我就不会检索到比客户想要查看的数据更多的数据?

时间:2015-03-25 19:08:22

标签: mongodb meteor

我有一个流星应用程序,我想让用户点击按钮在两个不同的数据过滤视图之间切换,比如" chart"状态为10或11的记录。应用程序的某些用户可能永远不希望看到状态10,而其他用户可能永远不希望看到状态11。

我试图找到一种通过发布/订阅的方式来最有效地解决这个问题...不要提取某些人不想看到的记录,同时还要减少网络流量。

第一个想法是以下...在服务器上发布状态参数:

  Meteor.publish("charts1", function (status) {
    console.log('someone subscribed to my publish of charts.. returning all charts now of status ' + status + " max 500 though");
    return Chart.find({"chartStatus": status}, {limit: 500, sort: {"demographics.lastName": 1}});
  });

然后,在客户端上,我有一个模板助手:

chartsOnClient: function () {
      return Chart.find({"chartStatus":Session.get('currentStatusFilter')}, {sort: {"demographics.lastName": 1}});
    }

和2个按钮,单击时将设置会话过滤器并同时订阅:

Template.addChartForm.events = {
    'click #mybutton10': function () {
      console.log("subscribing to to status 10...");
      Session.set('currentStatusFilter', 10);
      Meteor.subscribe('charts1', 10);
    },
    'click #mybutton11': function () {
      console.log("subscribing to status 11...");
      Session.set('currentStatusFilter', 11);
      Meteor.subscribe('charts1', 11);
    },
}

,当然,还有一个模板,它遍历" chartsOnClient"显示记录。

这很有效...当我点击button10时,我的模板中获得了状态10,然后点击button11在我的模板中给了我状态11 ...而且,额外的好处是,如果我从未点击过button11,我的本地客户端只保存状态10的记录,反之亦然,单击这两个按钮将填充我的本地集合与两个集合的联合。

我看到这个方法的唯一问题是,每次点击按钮都会产生服务器消息"有人订阅了我发布的图表......" ...表示客户端正在谈话到服务器并运行find方法。

我怀疑这不太理想...因为,如果我想,我可以移动2"订阅"在点击事件中调用外部,如下所示:

Meteor.subscribe('charts1', 10);
Meteor.subscribe('charts1', 11);

Template.addChartForm.events = {
    'click #mybutton10': function () {
      console.log("subscribing to to status 10...");
      Session.set('currentStatusFilter', 10);
    },
    'click #mybutton11': function () {
      console.log("subscribing to status 11...");
      Session.set('currentStatusFilter', 11);
    },
}

当我这样做时,我获得了相同的最终用户体验,但是,服务器控制台仅在启动时显示"有人订阅了我的发布" ...消息,而不是每次都单击按钮。

缺点是两组记录都会被拉到每个用户的客户端,甚至是那些可能永远不会点击这两个按钮的用户。但好处是每次点击切换数据视图时都不会调用subscribe方法......

我有什么不明白的吗?哪种方法最好?是否有更好的方法来完成这项工作?我是meteor和mongo的新手。

谢谢。

编辑,基于@mattk,我将在按钮点击中进行订阅,但如果我已经订阅了该特定过滤器,则在会话变量中使用数组以防止第二次订阅:

'click #mybutton10': function () {
  Session.set('currentStatusFilter', 10);
  var filtersAppliedSoFar = Session.get('filtersAppliedSoFar');
  if (filtersAppliedSoFar.indexOf(10) == -1) {
    console.log("subscribing to to status 10...");
    filtersAppliedSoFar.push(10);
    Session.set('filtersAppliedSoFar', filtersAppliedSoFar);
    Meteor.subscribe('charts1', 10);
  }
},
'click #mybutton11': function () {
  Session.set('currentStatusFilter', 11);
  var filtersAppliedSoFar = Session.get('filtersAppliedSoFar');
  if (filtersAppliedSoFar.indexOf(11) == -1) {
    console.log("subscribing to status 11...");
    filtersAppliedSoFar.push(11);
    Session.set('filtersAppliedSoFar', filtersAppliedSoFar);
    Meteor.subscribe('charts1', 11);
  }
},

这样,我不会在用户点击特定过滤器之前提取数据,但如果他们在2个过滤器之间来回点击,我也不会重新订阅,这是预期的。< / p>

再次编辑:在询问此问题How do you securely log out and clear all subscriptions?并转向订阅管理器https://github.com/meteorhacks/subs-manager后,我发现订阅管理器实现了我在这里寻找的内容:我不希望它发生如果我的客户再次调用.subscribe,则第二次服务器。不使用会话变量(filtersAppliedSoFar)来了解客户端是否已经订阅,子管理器会自动跟踪这个...我只是在订阅管理器对象上调用.subscribe,它不会命中服务器第二次。 ..然后额外的好处是我可以在注销时调用.clear()并停止所有订阅。

1 个答案:

答案 0 :(得分:4)

你的第一个模式没有任何问题。每当你与服务器交谈时,你想要它或者告诉它一些新东西,这正是你正在做的事情:你只需要它来获取你需要的数据。如果要减少带宽,请限制返回的fields;您可能不需要存储在文档中的每个字段。

我遵循这样的事情:

//Client code (event click)
Meteor.subscribe('patients',
  {"chartStatus":Session.get('currentStatusFilter')}, 
  {
    fields: {'demographics': 1, 'chartStatus': 1},
    sort: {"demographics.lastName": 1}
  });

//Server code
Meteor.publish('patients', function(query, options) {
  if (options) {
    check(options, {
      sort: Match.Optional(Object),
      limit: Match.Optional(Number),
      fields: Match.Optional(Object)
    });
  }
  return Patients.find(query,options);
});

请注意,客户现在可以询问她想要的任何字段。如果将来文档中的某些字段不应通过网络发送,您也需要进行权限检查。现在,这对你来说似乎不是一个问题,因为你已经发送了整个文档。