【问题标题】:Apply limit to each condition in an $or query?对 $or 查询中的每个条件应用限制?
【发布时间】:2015-09-22 12:01:40
【问题描述】:

我有一个使用 MongoDB 用 Meteor 编写的聊天室应用程序。每个聊天室包含许多消息,一个用户可以加入多个聊天室。我想创建一个查询,从每个聊天室中获取给定用户所在的所有聊天室的 200 条最新消息。我正在做这样的事情:

// These are the ids of the chatrooms the user is currently in var conditions = [{chatroomId: 1}, {chatroomId: 2}]; Messages.find({$or: conditions}, {sort: {createdAt: -1}, limit: 200});

但是,这个限制自然适用于整个查询;所以用户最终可能会收到来自一个房间的 180 条消息和来自另一个房间的 20 条消息。更糟糕的是,随着新消息的添加,哪个房间的旧消息被剔除是不一致的。

我可以随着用户加入更多聊天室而增加限制,但这可能会导致他们在两个聊天室中有 5 条消息,而在第三个聊天室中有 590 条消息。

有没有办法对 or 中的每个条件应用切片或限制?我将其作为 Meteor 出版物发布,因此我需要返回单个光标。

【问题讨论】:

  • 您不能这样做,因为“限制”适用于整个结果集,而不仅仅是选择中的单个条件。正如您应该能够想象的那样,您实际上想要几个查询的组合结果。您可以使用async.concat 或任何其他形式来执行此服务器端,您可以将多个查询的结果组合在一起,最好是并行执行。但这确实意味着几个查询。使用 `.aggregate() 是“可能的”,但这确实意味着保留整个列表,然后删除结果。不适合 200 件商品
  • 不幸的是,如果您在一个数组中返回多个游标,它们当前必须都来自不同的集合。否则,您可能只是将每个聊天室的游标推入一个数组并返回游标数组。 Meteor 希望“在未来解除限制”。

标签: mongodb meteor


【解决方案1】:

您不能仅对结果集的一部分应用限制,因此实现此目的的唯一方法是使用多个订阅。这是一些使用模板订阅的示例代码。您需要针对您的特定用例对其进行修改。

服务器

// Returns a limited set of messages for one specific chat room.
Meteor.publish('messages', function(chatroomId, limit) {
  check(chatroomId, String);
  check(limit, Number);

  var options = {sort: {createdAt: -1}, limit: limit};
  return Messages.find({chatroomId: chatroomId}, options);
});

客户

Template.myTemplate.helpers({
  messages: function() {
    // Read all of the messages (you may want to restrict these by room),
    // sort them, and return the first 100 across all.
    return _.chain(Messages.find().fetch())
      .sortBy(function(message){return -message.createdAt.getTime();})
      .first(100)
      .value();
  }
});

Template.myTemplate.onCreated(function() {
  // Subscribe to multiple chat rooms - here we are assuming the ids are
  // stored in the current context - modify this as needed for your use case.
  this.subscribe('messages', this.chatroomId1, 100);
  this.subscribe('messages', this.chatroomId2, 100);
});

【讨论】:

  • 如果聊天室的数量很大而每个聊天室中的消息数量很少,这似乎真的很慢。
  • 同意。作为用户所属聊天室数量的函数,这变得令人不快。选择限制可能有更好的启发式方法,例如如果有 > 5 个房间,则将限制减少到每个 20 个。如果此设置证明无法管理,那么我建议更改问题的性质。也许将每个用户的最后 N 条消息存储在单独的集合中。
  • 如何将结果服务器端复制到临时集合中?如果您只查看字段的子集,可能会更快。然后可以一口气发布。
  • 看起来 Meteor 不支持 Mongo 的 cloneCollection(),这会更容易/更快。
【解决方案2】:

我相信,简单地使用.find()s 的动态数量,每个房间一个,就可以解决这种情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 1970-01-01
    • 2021-12-29
    • 2012-12-03
    相关资源
    最近更新 更多