Best way to do this Subscription/Publication

I would like to share this doubt, and how would you do it.

Imagine that I have 2 collections, ‘Books’ and ‘Authors’. Every document in the book collection has an author field with an ‘_id’ reference to the specific author in the ‘Authors’ Collection.

Now I want to show in the client a list of my books. I can do a simple subscription to 10 books, and show them in a list. The problem comes when I want to show the name of the author. I would do it like this:

list.html

{{ #each book in books }}
	{{ book.title }}
	...
	{{ authorName book.authorId }}
{{ /each }}

list.js

...helpers({
	books: function () {
		return Books.find();
	},

	authorName: function (id) {
		return Authors.findOne({ _id: id }).name;
	}
})

The problem is that I have to subscribe to all the ‘Authors’ collection. With a small collection is not a problem. But imagine that I have 5000 authors.

How would you do it?

Best solution here is to publish using a package like Publish Composite. Also, if you have 10,000 books, only publish a small subset for each subscription to maintain performance.

2 Likes

If you didn’t want to head down the publish composite route:

Meteor.publish('books', function () {

  let books = Books.find({}, { limit: 10 });

  // Grab the relevant ids
  let authorIds = _.pluck(books.fetch(), 'authorId');

  // Scope your query and result
  let authors = Authors.find({ _id: { $in: authorIds } }, { fields: { _id: 1, name: 1 } });

  // Return only the docs you need
  return [books, authors];

});

this does not work, with the change in data the meteor update the cursor but does not run the publish method again so authorIds are from the old cursor. https://www.discovermeteor.com/blog/reactive-joins-in-meteor/

I do not like publish composite because it is creating a subscription for each author, and it is going to make your system so slow!

what I ended up doing and haven’t seen anywhere is just publish it the way @vigorwebsolutions suggested but use subscribe manager package. on the client in the helper (for Blaze) or another place check the data, if you don’t have an author of a book in your minimongo just restart the subscribe and you will get a new set of data. it works great for me.

Yeah, I should’ve mentioned that there are caveats to that solution. I agree that publish composite can be overkill/taxing on the server when it’s not always needed.

Also, I’ve been looking more at non-reactive solutions when they make sense, and book-author seemed to fit that paradigm for me.

It wouldn’t create a subscription for each author… Maybe you mean it would make a query per book to get the record of the author, you are right. The really awesome thing about Mongodb is that query’s on indexes (especially _id’s) are super fast, so as long as you limit your books query reasonably (say 30 books at a time), your performance shouldn’t suffer.

1 Like

First, I’d start with optimizing the database schema, before I do any publication magic that will slow down the servers.

Just provide the name of the author in your book collection together with his id. Mongo is a NoSQL database and fully supports this way of structuring. And it’s not like you’re going to change the author’s name for a book every week.