41

ドキュメントからこの例を完全に理解するのに苦労しています...私はそれがどのように機能するかなどを観察できるように、さまざまな方法で実行してみました。

これをどのように購読しますか?これを機能させるために必要なクライアント側のコードを含めることはできますか?

というコレクションはありmessages-countますか?Roomメッセージのコレクションですか?例にコレクション定義を含めることはできますか?

これに関するヒントは素晴らしいでしょう!

:これは、この質問が最初に投稿されたとき(2012年5月)に表示されたコードです。今はもっと簡単です。

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

3 に答える 3

52

より明確な説明を書くように私に促してくれてありがとう。これが私のコメント付きのより完全な例です。私がクリーンアップしたいくつかのバグと矛盾がありました。次のドキュメントリリースではこれを使用します。

Meteor.publish非常に柔軟です。既存のMongoDBコレクションをクライアントに公開するだけではありません。必要なものは何でも公開できます。具体的には、クライアントがサブスクライブできる一連のドキュメントMeteor.publishを定義します。各ドキュメントは、コレクション名(文字列)に属し、一意のフィールドがあり、JSON属性のセットがあります。セット内のドキュメントが変更されると、サーバーはサブスクライブされた各クライアントに変更を送信し、クライアントを最新の状態に保ちます。 _id

ここでは"counts-by-room"、という名前のコレクションに単一のドキュメントを含む、という名前のドキュメントセットを定義します"counts"。ドキュメントには2つのフィールドがあります。1つroomIdは部屋のIDで、もう1つ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"引数は1つです。現在の部屋のIDです。クライアントが変更時に古い部屋のカウントから自動的にサブスクライブを解除し、新しい部屋のカウントに再サブスクライブする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.");
于 2012-05-12T19:47:34.007 に答える
2

Leonhardt Willeが言ったように、このソリューションの欠点は、meteorがアイテムのコレクション全体を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;
    }
}
于 2012-11-06T13:36:51.723 に答える
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ミリ秒の変更がない場合にのみサブスクリプションがフラッシュされます。

ヒントをくれた#meteorの@possibilitiesに感謝します。

于 2012-09-12T14:12:47.547 に答える