Need help displaying live data by polling mongo db

First of all, I am new to Meteor and Javascript, but I am trying my best to grasp the language.

Need help with displaying live data on a home page.
in the home.html i am calling this helper “part” and passing “45” as argument

<p>Price of No. 45 is {{part 45}}</p>

in home.js I am searching the Part database for an item that match the type I specified through the passed argument then sort it and finally, i try to return its value of its price key.

Template.home.helpers({
  part: function (type) {
    return Part.findOne({'type':type}, { sort: { createdAt: -1 }}).price;
  }
});

I am getting the following error, and I understand why because of the delay in retrieving data from the db.

Exception in template helper: TypeError: Cannot read property 'price' of undefined

What can I do to fix this? callback or something.

Thanks

It looks like the findOne query is not returning an object with a price property. Maybe check your Part publication on the server. Ensure the price field is being published. Also ensure you are subscribing to the correct Part subscription on the client.

I use React mainly, but {{price 45}} may be invalid syntax? Someone else may know better. Try moving 45 outside the double curly braces {{price}} 45.

Dear Johnner thanks for the reply, the findOne query does return the correct object, but after a little delay. I know this because after couple of attempts I see the correct price data. I just dont know how to hold the “.price” part of the code until the query has returned valid data. Any ideas?

It’s because at the first loading of the page, the Part is still empty, so, there is no price to retrieve. Try the following code:

Template.home.helpers({
part: function (type) {
return Part.findOne({‘type’:type}, { sort: { createdAt: -1 }}) && Part.findOne({‘type’:type}, { sort: { createdAt: -1 }}).price;
}
});

This is a good answer that should work. You could also modify your template to show a “page loading” message until all your subscriptions have loaded. It will look a little like (my syntax could be wrong)

{{ #unless Template.subscriptionReady() }}

loading...

{{ else }} Your page goes here {{ /unless }}

The important part here is the subscriptionsReady() call - but check the documentation as I may be using slightly the wrong name for it. This will stop the price from flashing onto the screen a little bit after the other boilerplate text around it has appeared.

By using a named property (price) of an object which may be undefined, you will cause JavaScript to raise an exception. That’s not a Meteor thing.

However, Meteor has reactivity baked into Blaze and will handle this without guard code or other checks. Sure, those techniques will work, but they aren’t necessary. You need to remove references to properties that may not be available (yet) and leave the destructuring and reactivity to Blaze. Here’s one way to do what you want:

<template name="home">
  {{#with part 45}}
    <p>Price of No. 45 is {{price}}</p>
  {{/with}}
</template>
Template.home.helpers({
  part(type) {
    return Part.findOne({type}, { sort: { createdAt: -1 }})
  }
});

(You’ll also notice you can use ES6 (and 7) notation in your code).

1 Like

The answer I am giving is not the best answer as the query is executed twice, but a simple one using The conditional (ternary) operator of Javascript.

Example:

return Collection.findOne({}) ? Collection.findOne({}).price:'NA'
Just another observation, please check if sort with findOne is correct or gives correct intended result. As findOne is supposed to fetch one record or the first record it finds.

The query is executed once in the {{#with}}. That sets the context, which includes the properties - in this case price - within the {{#with}} block.