Meteor server reactivity

2020-06-06 07:30发布

I have an app with two collections

Books = new Meteor.Collection("books");
Chapters = new Meteor.Collection("chapters");

where the documents look pretty much like this:

Book = {
  _id : BookId,
  users_who_can_view_this_book : [userId, userId]
}

Chapter = {
  book : BookId
}

On the server I publish books and chapters like this:

Meteor.publish('books', function() {
  return Books.find({ users_who_can_view_this_book : { $in : [this.userId] } });
});

Meteor.publish('chapters', function() {
  var bookIds = Books.find({
    users_who_can_view_this_book : {$in : [this.userId] }
  }).map(function(book) {
    return book._id;
  });
  return chapters.find({book: {$in : bookIds}});
});

On the client I just subscribe like this:

Meteor.subscribe('books');
Meteor.subscribe('chapters')

So, if a user has access to a book I want the client to receive the book and its corresponding chapters. This works fine on initial load.

Now, on the server I want to be able to add or remove users to/from the list on the book documents and when I do that, update the client with the new chapters. As of now, the client only get the update on the books, but the chapters referring to that book is not added/removed from the client.

I understand that I need to change the way my chapters publication work. I have looked at the docs for cursor.observe and cursor.observeChange, but I really cannot grasp how to use them in this case. I have also studied this answer but I dont get all of it. I'd be happy to explain what parts of that answer I have questions about but since it's a slightly different case I dont know if is relevant. Anyway, some guidance on this or a working example would be much appreciated!

标签: meteor
1条回答
▲ chillily
2楼-- · 2020-06-06 07:55

Totally untested, no-guarantees code, but replace your Meteor.publish('chapters') function with this:

Meteor.publish('chapters-for-me', function() {

  var self = this;

  var handle = Books.find({users_who_can_view_this_book : {$in : [self.userId] }}).observeChanges({

    added: function(id) {
      Chapters.find({book: id}).forEach(function(chapter) {
        self.added("chapters", chapter._id, chapter);
      });
    },

    removed: function(id) {
      Chapters.find({book: id}).forEach(function(chapter) {
        self.removed("chapters", chapter._id);
      });
    }
  });

  self.ready();

  self.onStop(function () {
    handle.stop();
  });

});

...and then change your subscriptions to this:

Meteor.subscribe('books');
Meteor.subscribe('chapters-for-me');

... and leave your collection declarations as they are.

I just wrote this on the fly, but at the very least it should steer you in the right direction on how to use observeChanges() to solve your problem.

Again, as mquandalle stated, it would probably be better if you put your Chapters documents inside your Book documents. With your current setup, if your Chapters collection starts to get really big, your server performance is going to take a significant hit.

Hope that helps!

查看更多
登录 后发表回答