Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In meteor, can pub/sub be used for arbitrary in-memory objects (not mongo collection)

I want to establish a two-way (bidirectional) communication within my meteor app. But I need to do it without using mongo collections.

So can pub/sub be used for arbitrary in-memory objects?

Is there a better, faster, or lower-level way? Performance is my top concern.

Thanks.

like image 478
Dave Avatar asked Oct 19 '14 22:10

Dave


People also ask

What is Meteor in Mongodb?

Meteor stores data in collections. To get started, declare a collection with new Mongo.

What is Meteor collection?

Collections are Meteor's way of storing persistent data. The special thing about collections in Meteor is that they can be accessed from both the server and the client, making it easy to write view logic without having to write a lot of server code.


2 Answers

Yes, pub/sub can be used for arbitrary objects. Meteor’s docs even provide an example:

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

  // observeChanges only returns after the initial `added` callbacks
  // have run. Until then, we don't want to send a lot of
  // `self.changed()` messages - hence tracking the
  // `initializing` state.
  var handle = Messages.find({roomId: roomId}).observeChanges({
    added: function (id) {
      count++;
      if (!initializing)
        self.changed("counts", roomId, {count: count});
    },
    removed: function (id) {
      count--;
      self.changed("counts", roomId, {count: count});
    }
    // don't care about changed
  });

  // Instead, we'll send one `self.added()` message right after
  // observeChanges has returned, and mark the subscription as
  // ready.
  initializing = false;
  self.added("counts", roomId, {count: count});
  self.ready();

  // Stop observing the cursor when client unsubs.
  // Stopping a subscription automatically takes
  // care of sending the client any removed messages.
  self.onStop(function () {
    handle.stop();
  });
});

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

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

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

In this example, counts-by-room is publishing an arbitrary object created from data returned from Messages.find(), but you could just as easily get your source data elsewhere and publish it in the same way. You just need to provide the same added and removed callbacks like the example here.

You’ll notice that on the client there’s a collection called counts, but this is purely in-memory on the client; it’s not saved in MongoDB. I think this is necessary to use pub/sub.

If you want to avoid even an in-memory-only collection, you should look at Meteor.call. You could create a Meteor.method like getCountsByRoom(roomId) and call it from the client like Meteor.call('getCountsByRoom', 123) and the method will execute on the server and return its response. This is more the traditional Ajax way of doing things, and you lose all of Meteor’s reactivity.

like image 161
Geoffrey Booth Avatar answered Nov 14 '22 23:11

Geoffrey Booth


Just to add another easy solution. You can pass connection: null to your Collection instantiation on your server. Even though this is not well-documented, but I heard from the meteor folks that this makes the collection in-memory.

Here's an example code posted by Emily Stark a year ago:

if (Meteor.isClient) {
  Test = new Meteor.Collection("test");
  Meteor.subscribe("testsub");
}

if (Meteor.isServer) {
  Test = new Meteor.Collection("test", { connection: null });
  Meteor.publish("testsub", function () {
    return Test.find();
  });

  Test.insert({ foo: "bar" });
  Test.insert({ foo: "baz" });
}
like image 22
Dave Avatar answered Nov 15 '22 01:11

Dave