Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Meteor, how can I query only the records of a given subscription?

Tags:

meteor

I understand that a a subscription is a way to flow records into a client-side collection, from this post, and others...

However, per this post, You can have multiple subscriptions that flow into the same collection.

// server
Meteor.publish('posts-current-user', function publishFunction() {
  return BlogPosts.find({author: this.userId}, {sort: {date: -1}, limit: 10});
  // this.userId is provided by Meteor - http://docs.meteor.com/#publish_userId
}
Meteor.publish('posts-by-user', function publishFunction(who) {
  return BlogPosts.find({authorId: who._id}, {sort: {date: -1}, limit: 10});
}

// client
Meteor.subscribe('posts-current-user');
Meteor.subscribe('posts-by-user', someUser);

Now - I obtained my records via two different subscriptions, can I use the subscription to get to the records that it pulled back? Or must I requery my collection? What is the best practice for sharing that query between client and server?

I hope I'm not missing something obvious here, but executing the Meteor.subscribe function only for its side-effects seems to be losing a very useful piece of information - namely which subscription a record came from. Presumably the names of publications and subscriptions are chosen to be meaningful - it would be nice if I could get to records associated with that name.

like image 727
Dean Radcliffe Avatar asked Jan 02 '15 20:01

Dean Radcliffe


2 Answers

What you seem to want to do is maintain two separate collections of records, where each collection is populated by a different publication. If you read the DDP specification, you'll see that the server tells the client which collection (not publication) each record belongs to, and multiple publications can actually provide different fields to the same record.

However, Meteor actually lets you send records to any arbitrary collection name, and the client will see if it has that collection. For example:

if (Meteor.isServer) {
  Posts = new Mongo.Collection('posts');
}

if (Meteor.isClient) {
  MyPosts = new MongoCollection('my-posts');
  OtherPosts = new MongoCollection('other-posts');
}

if (Meteor.isServer) {
  Meteor.publish('my-posts', function() {
    if (!this.userId) throw new Meteor.Error();

    Mongo.Collection._publishCursor(Posts.find({
      userId: this.UserId
    }), this, 'my-posts');

    this.ready();
  });

  Meteor.publish('other-posts', function() {
    Mongo.Collection._publishCursor(Posts.find({
      userId: {
        $ne: this.userId
      }
    }), this, 'other-posts');

    this.ready();
  });
}

if (Meteor.isClient) {
  Meteor.subscribe('my-posts', function() {
    console.log(MyPosts.find().count());
  });

  Meteor.subscribe('other-posts', function() {
    console.log(OtherPosts.find().count());
  });
}
like image 114
sbking Avatar answered Nov 17 '22 08:11

sbking


This is what's happening:

Say that your server-side BlogPosts Mongo collection contains 500 posts from 10 different users. You then subscribe to two different subscriptions on the client:

Meteor.subscribe('posts-current-user'); // say that this has 50 documents
Meteor.subscribe('posts-by-user', someUser); // say that this has 100 documents

Meteor will see Meteor.subscribe('posts-current-user'); and proceed to download the posts of the current user to the client-side Mini-Mongo's BlogPosts collection.

Meteor will then see Meteor.subscribe('posts-by-user', someUser); and proceed to download the posts of someuser to the client-side Mini-Mongo's BlogPosts collection.

So now the client-side Mini-Mongo BlogPosts collection has 150 documents, which is a subset of the 500 total documents in the server-side BlogPosts collection.

So if you did BlogPosts.find().fetch().count in your client (Chrome Console) the result would be 150.

like image 22
fuzzybabybunny Avatar answered Nov 17 '22 06:11

fuzzybabybunny