If you're looking to achieve this join, there are a variety of methods you can utilize. But before we delve into the specifics, a few key points to keep in mind:
Sorting within the publish function does not impact document order on the client-side, as I mentioned in response to this query.
It's generally recommended to use the plural form when naming collections. For instance, using Course
for a collection of courses may appear odd.
This question primarily revolves around joins; hence, I suggest reading up on Reactive Joins In Meteor.
Server Transformation
To address your query directly, here's how you can transform the documents on the server end:
Meteor.publish 'popularCourses', ->
transform = (fields) ->
if fields.owner
username = Meteor.users.findOne(fields.owner)?.username
fields.owner = username
fields
handle = Course.find().observeChanges
added: (id, fields) =>
@added 'course', id, transform fields
changed: (id, fields) =>
@changed 'course', id, transform fields
removed: (id) =>
@removed 'course', id
@ready()
@onStop ->
handle.stop()
Benefits
- All processing takes place on the server, enabling the client to simply use
owner
as if it were a username.
Drawbacks
Utilizing observeChanges
might entail more computation than necessary for a basic join operation.
If courses are published elsewhere, the owner
field could get overwritten upon document merging on the client side. One potential workaround involves adding a field like ownerUsername
, though this would incur additional observe costs.
This method proves ineffective if the owner ID needs to be accessed on the client.
It lacks reactivity in scenarios where the username undergoes changes (albeit infrequently).
Non-Reactive Publish + Client-Side Join
You could implement the publish in the following manner:
CoffeeScript
Meteor.publish 'popularCourses', ->
courseCursor = Course.find()
userIds = courseCursor.map (c) -> c.owner
userCursor = Meteor.users.find {_id: $in: userIds}, {fields: username: 1}
[courseCursor, userCursor]
JavaScript
Meteor.publish('popularCourses', function() {
var courseCursor = Course.find();
var userIds = courseCursor.map(function(c) {return c.owner;});
var userCursor = Meteor.users.find(
{_id: {$in: userIds}},
{fields: {username: 1}
});
return [courseCursor, userCursor];
});
Ensure that only username
and _id
are published from
userCursor</code to avoid inadvertently disclosing hashed passwords and session data. Subsequently, you can perform the join on the client side as illustrated below:</p>
<pre><code>Template.myTemplate.helpers
courses: ->
Course.find().map (c) ->
c.owner = Meteor.users.findOne(c.owner)?.username
c
Advantages
Drawbacks
Additionally, you have the option of employing a package for achieving a fully reactive join. Nonetheless, unless the owner (or their username) undergo frequent alterations, such an approach might prove excessive.