Edit your documents before sending without too much stress
NOTE: this package is now called cottz:publish-relations and is hosted on https://github.com/Goluis/cottz-publish-relations
$ meteor add cottz:publish
provides a number of methods to easily manipulate data using internally observe and observeChanges in the server
Assuming we have the following collections
// Authors
{
_id: 'someAuthorId',
name: 'Luis',
profile: 'someProfileId',
bio: 'I am a very good and happy author',
interests: ['writing', 'reading', *others*]
}
// Reviews
{
_id: 'someReviewId',
authorId: 'someAuthorId',
book: 'meteor for pros',
text: 'this book is not better than mine'
}
// Books
{
_id: 'someBookId',
authorId: 'someAuthorId',
name: 'meteor for dummies'
}
// Comments
{
_id: 'someCommentId',
bookId: 'someBookId',
text: 'This book is better than meteor for pros :O'
}
I want publish the autor with his books
Meteor.publish('author', function (authorId) {
Publish.relations(this, Authors.find(authorId), function (id, doc) {
this.cursor(Books.find({authorId: id})).publish();
});
return this.ready();
});
and comments of the books
Meteor.publish('author', function (authorId) {
Publish.relations(this, Authors.find(authorId), function (id, doc) {
this.cursor(Books.find({authorId: id})).publish(function (id, doc) {
this.cursor(Comments.find({bookId: id})).publish();
});
});
return this.ready();
});
I also want to bring the profile of the author but within the author not apart
Meteor.publish('author', function (authorId) {
Publish.relations(this, Authors.find(authorId), function (id, doc) {
this.cursor(Books.find({authorId: id})).publish(function (id, doc) {
this.cursor(Comments.find({bookId: id})).publish();
});
doc.profile = this.cursor(Profiles.find(doc.profile))
.changeParentDoc(function (profileId, profile) {
return profile;
});
});
return this.ready();
});
I want to include the reviews of the author within this
Meteor.publish('author', function (authorId) {
Publish.relations(this, Authors.find(authorId), function (id, doc) {
this.cursor(Books.find({authorId: id})).publish(function (id, doc) {
this.cursor(Comments.find({bookId: id})).publish();
});
doc.profile = this.cursor(Profiles.find(doc.profile))
.changeParentDoc(function (profileId, profile) {
return profile;
});
doc.reviews = this.cursor(Reviews.find({authorId: id}))
.group(function (doc, index) {
return doc;
}, 'reviews');
});
return this.ready();
});
// doc.reviews = [{data}, {data}]
To finish I want to show only some interests of the author
Meteor.publish('author', function (authorId) {
Publish.relations(this, Authors.find(authorId), function (id, doc) {
this.cursor(Books.find({authorId: id})).publish(function (id, doc) {
this.cursor(Comments.find({bookId: id})).publish();
});
doc.profile = this.cursor(Profiles.find(doc.profile))
.changeParentDoc(function (profileId, profile) {
return profile;
});
doc.reviews = this.cursor(Reviews.find({authorId: id}))
.group(function (doc, index) {
return doc;
}, 'reviews');
doc.interests = this.paginate({interests: doc.interests}, 5);
});
return this.ready();
});
// doc.reviews = [{data}, {data}]
// Client
// skip 5 interest and show the next 5
Meteor.call('changePagination', 'authorId', 'interests', 5);
publishes a cursor, collectionName
is not required
observe or observe changes in a cursor without sending anything to the client. callbacks are the same as those used by meteor
- Note: sub will only be used to stop observers, if you not send it you have to stop manually
- You can edit the document directly (doc.property = 'some') or send it in the return.
- sub is the this of the publication
- options is an object like this:
{cursor: Authors.find(), name: 'authors'}
or just a cursor and the name will be the default name of the cursor - callback receives 3 parameters: (
id
,doc
,changed
)
after starting a Publish.relations you can use the methods in this
within the callback
allow you to use cursor methods in the cursor
collection
is the collection where the cursor will be sent. if not sent, is the default cursor collection name
page within an array without re run the publication or callback
- returns the paginated array, be sure to change it in the document
- field is an object where the key is the field in the document and the value an array
- limit the total number of values in the array to show
- infinite if true the above values are not removed when the paging is increased
- Meteor.call('changePagination', _id, field, skip) change the pagination of the document with that
id
andfield
. skip is the number of values to skip
after creating an instance of this.cursor
can use the following methods
publishes a cursor
- If you send a callback you can use relations methods again and you can edit the document directly (doc.property = 'some') or send it in the return.
observe or observe changes in the cursor without sending anything to the client. callbacks are the same as those used by meteor
designed to change something in the document with the return of the callbacks
.
- callbacks is an object with
added``changed``removed
or a function that executes when it is added and changed - onRemoved is a function that executes when is removed. is not used if callbacks is an object
returns an array of elements with all documents in the cursor. When there is a change it will update the element change in the resulting array and send it back to the document
- callback receive (
doc
,atIndex
) when is added and (doc
,atIndex
,oldDoc
) when is changed - field is the field in the main document that has the array
- options (not required) is an object like this:
{sort: array, sortField: '_id'}
implements changes based on the position within thesort
.sort
is an array of values andsortField
is the field of the document where they are, by default is the _id
- all cursors returns an object with the stop() method except for changeParentDoc, group and paginate
- all cursors are stopped when the publication stop
- when the parent cursor is stopped or a document with cursors is removed all related cursors are stopped
group
use observe with absolute position information (addedAt, changedAt, removedAt), if possible try using onlypublish
to maintain performance- if when the callback is re-executes not called again some method (within an If for example), the method continues to run normally, if you re-call method (because the query is now different) the previous method is replaced with the new
I keep all cursors by name and if within the same instance is called at the same cursor will stop the first and second replace him
Meteor.publish('movie', function (directorId) {
Publish.relations(this, Movies.find({director: directorId}), function (id, doc) {
this.cursor(Meteor.users.find({_id: directorId})).publish(); // this cursor will not receive updates
this.cursor(Meteor.users.find({_id: doc.producerId})).publish();
});
return this.ready();
});
you can avoid this problem in the following two ways
Meteor.publish('movie', function (directorId) {
Publish.relations(this, Movies.find({director: directorId}), function (id, doc) {
this.cursor(Meteor.users.find({_id: directorId}).publish(function () {
this.cursor(Meteor.users.find({_id: doc.producerId})).publish();
});
});
return this.ready();
});
this is much better than the first way
Meteor.publish('movie', function (directorId) {
Publish.relations(this, Movies.find({director: directorId}), function (id, doc) {
this.cursor(Meteor.users.find({_id: directorId}), 'users').publish(); // users is the default of Meteor.users
this.cursor(Meteor.users.find({_id: doc.producerId}), 'producers').publish();
});
return this.ready();
});