Code Monkey home page Code Monkey logo

Comments (6)

mitar avatar mitar commented on May 24, 2024

How you would make it on the client-side using autorun and Minimongo queries? Do the same on the server side.

from meteor-reactive-publish.

thebarty avatar thebarty commented on May 24, 2024

OK, got it...

maybe you want to add this code to your README as a multiple-cursor example?

Meteor.publish('all-posts-with-comments-and-authors', function () {
  this.autorun(function (computation) {
    const posts = Posts.find({})

    // aggregate authors and comments
    const authorIds = []
    let commentIds = []
    posts.forEach(function (post) {
      authorIds.push(post.authorId)
      commentIds = _.union(commentIds, post.commentIds)
    })
    const authors = Authors.find({ _id: { $in: authorIds } })
    const comments = Comments.find({ _id: { $in: commentIds } })

    // return multiple cursors
    return [posts, authors, comments]
  })
})

from meteor-reactive-publish.

mitar avatar mitar commented on May 24, 2024

Great! But just for the record, M2M joins are inefficient because at any change of any document, the whole autorun will rerun, republishing all documents. Only changes will be send to the client, so that is good, but this still means that diffs with previous documents will have to be computed. So, it is not so efficient.

I am not sure if this works (not tested the code), but probably this could be better:

Meteor.publish('all-posts-with-comments-and-authors', function () {
  this.autorun(function (computation) {
    const posts = Posts.find({}, {fields: {commentIds: 1}});

    // aggregate comments
    let commentIds = [];
    posts.forEach(function (post) {
      commentIds = _.union(commentIds, post.commentIds);
    });

    return Comments.find({ _id: { $in: commentIds } });
  });

  this.autorun(function (computation) {
    const posts = Posts.find({}, {fields: {authorId: 1}});

    // aggregate authors
    const authorIds = [];
    posts.forEach(function (post) {
      authorIds.push(post.authorId);
    });

    return Authors.find({ _id: { $in: authorIds } });
  });

  return Posts.find({});
});

Here, we limit reactivity inside each autorun only really to fields we care about. So instead of autorun rerunning on any change of any fields of any document, we make it rerun only when really just data we care about changes.

Personally, I simply use multiple publish functions, or PeerDB, for such use cases.

from meteor-reactive-publish.

mitar avatar mitar commented on May 24, 2024

(Reopening until I document this.)

from meteor-reactive-publish.

mitar avatar mitar commented on May 24, 2024

If you want to optimize it even further (but please profile if it really optimizes anything), you could do even something crazy like:

const allCommentsIds = new ComputedField(function () {
  const posts = Posts.find({}, {fields: {commentIds: 1}});

  // aggregate comments
  let commentIds = [];
  posts.forEach(function (post) {
    commentIds = _.union(commentIds, post.commentIds);
  });

  // so that set-equality is easy
  commentIds.sort();

  return commentIds;
}, EJSON.equals);

const allAuthorsIds = new ComputedField(function () {
  const posts = Posts.find({}, {fields: {authorId: 1}});

  // aggregate authors
  const authorIds = [];
  posts.forEach(function (post) {
    authorIds.push(post.authorId);
  });

  // so that set-equality is easy
  authorIds.sort();

  return authorIds;
}, EJSON.equals);

Meteor.publish('all-posts-with-comments-and-authors', function () {
  this.autorun(function (computation) {
    return Comments.find({ _id: { $in: allCommentsIds() } });
  });

  this.autorun(function (computation) {
    return Authors.find({ _id: { $in: allAuthorsIds() } });
  });

  return Posts.find({});
});

The difference here is that now computed field assures autorun will rerun only if content of IDs array really changes. Moreover, I moved computed fields out of the autorun. In this way it can be shared between multiple subscriptions.

BTW, you should also ask yourself if you really need M2M here. For example, is it really possible to have a comment without a post? If you want to publish all posts, then probably you can just go and publish all comments as well. There is no way to have a comment without a post anyway. And it might be then also useful to also simply publish all authors as well. For example, I often maintain count of how many posts each author has made anyway in the author's document. So you could blindly publish all authors which have the count larger than 0. So then you do not need any joins and any reactivity. Very performant.

A different story is if you need some parameters to pass. Like posts of only one author or something like that.

So, personally in MongoDB world an non-relational databases world it is pretty normal to denormalize data and then you can have quick queries. In general the idea is that you design your schemas according to queries you will be making. In most cases you do not need to support arbitrary queries, but only some known set of queries for your app, so you make a schema which has always all necessary fields for your queries in one document. And then it is really quick to make queries, because even database does not have to consult multiple tables, which means that you can do horizontal scaling very easily (joins across horizontally scaled instances is hard). I use PeerDB for automatic and reactive denormalization.

from meteor-reactive-publish.

mitar avatar mitar commented on May 24, 2024

Closing because I think this is not the best way to use this package.

from meteor-reactive-publish.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.