Подтвердить что ты не робот

Как работает пример сообщений в документах Meteor?

Не удалось полностью понять этот пример из документов... Я попытался запустить его по-разному, чтобы я мог наблюдать, как он работает, и т.д.

Как вы подписаны на это? Можем ли мы включить код на стороне клиента, необходимый для выполнения этой работы?

Есть ли коллекция под названием messages-count? Является ли Room набором сообщений? Можем ли мы включить определения коллекции в пример?

Любые советы по этому поводу будут замечательными!

ПРИМЕЧАНИЕ. Это код, который появился, когда этот вопрос был первоначально опубликован (май 2012 г.). Теперь это проще.

// server: publish the current size of a collection
Meteor.publish("messages-count", function (roomId) {
  var self = this;
  var uuid = Meteor.uuid();
  var count = 0;

  handle = Room.find({room_id: roomId}).observe({
    added: function (doc, idx) {
      count++;
      self.set("messages-count", uuid, "count", count);
      self.flush();
    },
    removed: function (doc, idx) {
      count--;
      self.set("messages-count", uuid, "count", count);
      self.flush();
    }
    // don't care about moved or changed
  });

  // remove data and turn off observe when client unsubs
  self.onStop(function () {
    handle.stop();
    self.unset("messages-count", uuid, "count");
    self.flush();
  });
});
4b9b3361

Ответ 1

Спасибо, что попросил меня написать более четкое объяснение. Вот более полный пример с моими комментариями. Было несколько ошибок и несоответствий, которые я очистил. Следующий выпуск docs будет использовать это.

Meteor.publish довольно гибкий. Он не ограничивается публикацией существующих коллекций MongoDB клиенту: мы можем публиковать все, что захотим. В частности, Meteor.publish определяет набор документов, на которые может подписаться клиент. Каждый документ принадлежит некоторому имени коллекции (строка), имеет уникальное поле _id, а затем имеет некоторый набор атрибутов JSON. По мере изменения документов в наборе сервер отправит изменения каждому подписчиваемому клиенту, обновив клиент.

Мы собираемся определить здесь набор документов, называемый "counts-by-room", который содержит один документ в коллекции с именем "counts". Документ будет иметь два поля: a roomId с идентификатором комнаты и count: общее количество сообщений в этой комнате. Нет реальной коллекции MongoDB с именем counts. Это просто имя коллекции, которую наш сервер Meteor будет отправлять клиенту, и хранить в клиентской коллекции с именем counts.

Для этого наша функция публикации принимает параметр roomId, который будет поступать от клиента, и наблюдает за запросом всех сообщений (определенных в другом месте) в этой комнате. Мы можем использовать более эффективную форму observeChanges наблюдения запроса здесь, так как нам не нужен полный документ, просто знание о том, что новый был добавлен или удален. В любое время, когда добавляется новое сообщение с roomId, которое нам интересно, наш обратный вызов увеличивает внутренний счетчик, а затем публикует новый документ клиенту с этим обновленным итогом. И когда сообщение удаляется, оно уменьшает счетчик и отправляет клиенту обновление.

Когда мы сначала вызываем observeChanges, некоторое количество обратных вызовов added будет запускаться сразу же, для каждого уже существующего сообщения. Затем будущие изменения будут срабатывать при каждом добавлении или удалении сообщений.

Наша функция публикации также регистрирует обработчик onStop для очистки, когда клиент отписывает (либо вручную, либо отключается). Этот обработчик удаляет атрибуты от клиента и срывает запущенный observeChanges.

Функция публикации запускается каждый раз, когда новый клиент подписывается на "counts-by-room", поэтому каждый клиент будет иметь observeChanges от своего имени.

// server: publish the current size of a collection
Meteor.publish("counts-by-room", function (roomId) {
  var self = this;
  var count = 0;
  var initializing = true;

  var handle = Messages.find({room_id: roomId}).observeChanges({
    added: function (doc, idx) {
      count++;
      if (!initializing)
        self.changed("counts", roomId, {count: count});  // "counts" is the published collection name
    },
    removed: function (doc, idx) {
      count--;
      self.changed("counts", roomId, {count: count});  // same published collection, "counts"
    }
    // don't care about moved or changed
  });

  initializing = false;

  // publish the initial count. `observeChanges` guaranteed not to return
  // until the initial set of `added` callbacks have run, so the `count`
  // variable is up to date.
  self.added("counts", roomId, {count: count});

  // and signal that the initial document set is now available on the client
  self.ready();

  // turn off observe when client unsubscribes
  self.onStop(function () {
    handle.stop();
  });
});

Теперь, на клиенте, мы можем рассматривать это как обычную подписку на Meteor. Во-первых, нам нужен Mongo.Collection, который будет содержать наш рассчитанный документ подсчета. Поскольку сервер публикует коллекцию с именем "counts", мы передаем "counts" в качестве аргумента конструктору Mongo.Collection.

// client: declare collection to hold count object
Counts = new Mongo.Collection("counts");

Тогда мы можем подписаться. (Вы действительно можете подписаться перед объявлением коллекции: Meteor будет помещать входящие обновления в очередь, пока там не будет места для их размещения.) Имя подписки "counts-by-room", и оно принимает один аргумент: текущий идентификатор комнаты. Я обернул это внутри Deps.autorun, чтобы при изменении Session.get('roomId') клиент автоматически отменил подписку на счет старого номера комнаты и повторно отправил подписку на новый номер комнаты.

// client: autosubscribe to the count for the current room
Tracker.autorun(function () {
  Meteor.subscribe("counts-by-room", Session.get("roomId"));
});

Наконец, у нас есть документ в counts, и мы можем использовать его так же, как и любую другую коллекцию Mongo на клиенте. Любой шаблон, который ссылается на эти данные, будет автоматически перерисовываться всякий раз, когда сервер отправляет новый счет.

// client: use the new collection
console.log("Current room has " + Counts.findOne().count + " messages.");

Ответ 2

Как сказал Леонхардт Вилле, недостатком этого решения является то, что метеор загружает всю коллекцию предметов с сервера Mongo, чтобы подсчитать их. Его решение в gist.github.com/3925008 лучше, но счетчик не будет обновляться при вставке новых элементов.

Вот мое реактивное решение

Коллекции:

Players = new Meteor.Collection("players");
PlayersCounts = new Meteor.Collection("players_counts")

Сервер:

Meteor.publish("players_counts", function(){
    var uuid = Meteor.uuid()
    var self = this;

    var unthrottled_setCount = function(){
        cnt = Players.find({}).count()
        self.set("players_counts", uuid, {count: cnt})
        self.flush()
    }

    var setCount = _.throttle(unthrottled_setCount, 50)

    var handle = Meteor._InvalidationCrossbar.listen({collection: "players"}, function(notification, complete){
        setCount();
        complete();
    })

    setCount();
    self.complete()
    self.flush()

    self.onStop(function(){
        handle.stop();
        self.unset("players_counts", uuid, ["count"]);
        self.flush();
    });
});

Клиент:

Meteor.subscribe("players_counts")

Template.leaderboard.total = function(){
    var cnt = PlayersCounts.findOne({})
    if(cnt) {
        return cnt.count;
    } else {
        return null;
    }
}

Ответ 3

Просто нашел решение проблемы, когда self.flush() отправляет тысячи обновлений клиенту - просто используйте _.debounce при подсчете:

count = 0
throttled_subscription = _.debounce =>
  @set 'items-count', uuid, count: count
  @flush()
, 10
handle = Items.find(selector).observe
  added: =>
    count++
    throttled_subscription()
  removed: =>
    count--
    throttled_subscription()

Это установит счетчик и сбросит подписку после 10 м без изменений.

Благодаря @possibilities на #meteor для подсказки.