Вопрос по mongodb, javascript, publish-subscribe, meteor – Как работает пример подсчета сообщений в Meteor docs?

41

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

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

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

Любые советы по этому вопросу будут великолепны!

NOTE: это код, который появился, когда этот вопрос был впервые опубликован (май 2012 г.). Теперь это проще.

<code>// 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();
  });
});
</code>

Ваш Ответ

4   ответа
0

если handle.stop () будет закомментирован? Посмотрите этот пример, это не работает, потому что мне нужно поместить onStop () внутри этой функции: checkSharedBy () ??

Meeteor, Отношения один-ко-многим и добавить поле только в коллекцию на стороне клиента в Publish?

2

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

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

Collections:

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

Server:

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

Client:

Meteor.subscribe("players_counts")

Template.leaderboard.total = function(){
    var cnt = PlayersCounts.findOne({})
    if(cnt) {
        return cnt.count;
    } else {
        return null;
    }
}
В Метеоре 0.6.6.3 (возможно, раньше) этот код не работает:Exception from sub CfuTiQGacmWo5xMsb TypeError: Cannot call method 'listen' of undefined russellfeeed
Просто к вашему сведению, это предварительный код Meteor 0.6. Смотрите обновленный ответ @debergalis выше. Andrew Mao
0

когда 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 мс без изменений.

Спасибо @ возможности на # метеор за подсказку.

Недостатком этого решения является то, что метеор загружает всю коллекцию на сервер, поэтому, если вы используете относительно медленное удаленное подключение к вашей mongoDB, будет существенная задержка после запуска вашего приложения (по крайней мере, если у вас есть 10 тыс. Документов в твоя БД похожа на меня). Leonhardt Wille
нашел решение - Gist.github.com / 3925008 Leonhardt Wille
52

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

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

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

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

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

Наша функция публикации также регистрируетonStop handler для очистки, когда клиент отписывается (либо вручную, либо при отключении). Этот обработчик удаляет атрибуты с клиента и сносит запущенный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.");
Как временное решение, можно исправить, вы можете перевести вызов наself.flush(); вadded с помощьюsetTimeout трюк, такой как: clearTimeout (t); t = setTimeout (function () {self.flush ();}, 10); matb33
@ matb33, есть ли лучшее решение проблемы сброса? Leonhardt Wille
Обратите внимание, чтоself.flush(); вadded отправит эту подписку клиенту при заполнении коллекции. Представьте, что у вас есть 1,000,000 «Сообщения» в этом «room_id». Вам будет отправлено 1 000 000 подписок, начиная с 1-го и заканчивая 1 000 000. Это заблокирует ваш браузер на некоторое время! Не говоря уже о количестве данных, летящих по проводам ... matb33
Nevermind, только что увидел твой код ниже! Похоже, вы поняли это matb33
Ясно, как колокол! Большое спасибо, что нашли время, чтобы уточнить это для меня! Mike Bannister

Похожие вопросы