Incorporating data from a different MongoDB collection before sending it through Meteor's publish functionality

My objective for is to showcase the usernames of course authors (referred to as "owners" of a document).

  • This is what I need to achieve:
    1. Display the usernames of course authors.

The code snippet below reflects my current approach:

Meteor.publish 'popularCourses', ->
# find all courses
  courses = Course.find({}, {sort: {createdAt: -1}}).fetch()
  for course in courses
# find each User by course owner
    owner = Meteor.users.findOne({_id: course.owner})
# overwrite the ownerId with the desired username
    course.owner = owner.username
  return courses

When auto-publishing is enabled, everything works fine. However, when it's off (as shown in the image), the author's name only appears if the current user matches the author.

--

A friend suggested the following solution: https://gist.github.com/wiesson/1fd93d77ed9df353b7ab

"The basic idea was to attach the username to the course before providing the data with the publish method. However, as described in Meteor MongoDB find / fetch issues, the publish method should return a cursor and not an array of objects.”

Any suggestions on how to address this issue? Should I store the owner usernames in an array? If so, how would I go about doing that?

P.S.: The source code can be accessed here (note that it has more commits than the deployed version): https://github.com/Crowducate/crowducate.me

Thank you in advance.

Answer №1

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

  • The publish function is lightweight in terms of computational resources and straightforward to implement.

  • Reacts promptly to username modifications.

Drawbacks

  • Lacks reactivity in case of owner modifications.

  • You'll need to execute the join on the client side. An intriguing alternative involves leveraging tools like Collection Helpers.

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.

Answer №2

An effective approach could involve simultaneously releasing both topCourses and creators, then assigning the creator to each course in the client side using identical code from the initial publication.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Delayed response of text effects in JQuery on page load

Within my rails app, I have the following code snippet: window.onload = -> $("#mycontainer").typewriter() $("#div1").fadeIn("slow") This code snippet interacts with the following block of content: <blockquote class="pull-left"> < ...

"Verifying in Javascript results in the inclusion of the item in

Can you check out this checkbox... <input type="checkbox" name="num" id="1" value="1" class="input-hidden" /> <input type="checkbox" name="num" id="3" value="3" class="input-hidden" /> <input type="checkbox" name="num" id="6" value="6" c ...

Shut the offcanvas using a button

I am having trouble closing the offcanvas using the close button inside the offcanvas itself. Currently, I can only close it with the button that I used to open it. What mistake did I make? Please refer to the code snippet below. (function mainScript( ...

Display numerical data at precise locations above an image

Currently, I am working on a project where I am adding multiple marker pins to an image and saving their positions (x and y coordinates) to a database for later use. To see the code I have written so far, you can visit this link: https://jsfiddle.net/at3w ...

Issue with the constraints in scipy.optimize.lsq_linear function

I am attempting to adjust the formula provided in the following link: http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.lsq_linear.html#scipy.optimize.lsq_linear Although I have the code below, it seems that it only accepts one tuple for ...

The latest iteration of three.js appears to disrupt how light is reflected on meshes

After upgrading from three.js version r110 to r124 for the new features, I noticed a significant change in the way my meshes reflect light. Suddenly, everything looks different and it's quite disappointing! ...

Maximizing the efficiency of a personalized hook that facilitates data sharing in React

I have developed a unique Custom Hook that looks like the following: import { useEffect, useState } from 'react'; import axios from 'axios'; const myCustomHook = () => { const [countries, setCountries] = useState([]); const [i ...

Arrow functions do not function properly with Typescript decorators

I've created a typescript decorator factory that logs the total time taken to execute a function, along with the actual function execution results and parameters passed to the decorator. For example: export function performanceLog(...args: any[]) { ...

Unable to locate the TabBar Review Icon while on the Settings screen

Every time I navigate to the settings screen, the Review Icon (favorite) disappears. However, it reappears when I go back to the Review screen. Can anyone explain why this is happening? Here is a screenshot I captured along with a snippet of code from my p ...

Ways to address issues in my tree-building algorithm when the parent ID is missing

Currently, I'm in the process of creating a function to build a tree. Everything seems to be functioning correctly until I encounter a scenario where a document is added with a parentID that doesn't exist in the list. The root node is intended to ...

Enabling and Disabling Input based on Conditions in Vue.js

Here is an example of an input field: <input type="text" id="name" class="form-control" name="name" v-model="form.name" :disabled="validated ? '' : disabled" /> ...

There seems to be a problem with how the navbar is being displayed in ResponsiveSlides.js

I am currently using WordPress, but I have come here seeking help with a jQuery/CSS issue. I am utilizing responsiveSlides.js to create a simple slideshow, however, when viewing it here at gallery link, it appears that something is not quite right. STEPS: ...

Checking for the presence of the key name "item[]" within an object in AngularJs

I currently have an object called "obj" with two keys: "goal" and "item[]". It looks like this: var obj = {goal:"abc",item[]:"def"}; These keys and values are dynamically generated. Now here's the problem - I need to determine if these keys exist ...

Obtain a result value from MySQL in Node.js

I need help retrieving a value from a select SQL query in Node.js. When I try to return the value, it comes back as undefined. I understand that it's an asynchronous function, but I'm struggling with how to handle it. I even tried assigning it to ...

Issue with query search functionality in API is preventing it from working efficiently

I am attempting to retrieve all records from MongoDB that start with the letter S, but every time I try, it only returns an empty array []. I am using the Params tab on Postman for this task. Here is the code I have written along with a snippet from Postma ...

How can I retrieve a Long Integer and store it in a Byte Array using VBA

Does anyone know how to generate a random Long Int number (4 bytes) and store it in the last 4 bytes of a byte array (byte array defined as Dim MybyteArray(1 to 16) As Byte)? I've been struggling to find a straightforward solution for this. Any sugges ...

Is there an easy method to verify if the local storage is devoid of any data?

Query is named aptly; seeking to verify in a conditional statement. ...

Constantly changing the size of an IFrame due to CSS View Height

I am facing an unusual issue with the CSS property vh (viewpoint height), causing my iframe to expand uncontrollably. To explain, within my iframe code, I have the following: function sendPost() { setInterval(funct ...

Creating a new instance in C# by combining a struct, an enum, and

Recently, I came up with an idea to create a struct which I named Example. Here is the structure: [System.Serializable] public struct Example { public enum Categories {example, test} [SerializeField] private Categories lineCategory ; public ...

Navigate to a new tab and reload the current page

Page.ClientScript.RegisterStartupScript(Page.GetType(), null, "window.open('bill_invoice.aspx?Number=" + txt_billNo.Text + "', '_blank')", true); This is a new tab for the bill invoice. Page.ClientScript.RegisterStartupScript(Page.Get ...