Alaister Young
Alaister Young

Reputation: 357

Using the .find().fetch() from within a function in Meteor

I am making a project with Meteor and I'm having some issues trying to get data out of mongodb in JavaScript. I have the following in a function:

console.log(Time.find({today: "Saturday"}).fetch());

In my publish.js file on the server side I have the following:

Meteor.publish("time", function () {
  var currentUserId = this.userId;
  return Time.find({user: currentUserId});
});

And In my subscriptions file I have the following:

Meteor.subscribe("time");

This function gets called later down in the code but it returns an empty array. If I run this code in my browsers console it returns an array with 2 objects in it, which is correct. This leads me wondering if I can use the .fetch() function from within my code? As if I leave off the .fetch() it returns what looks like the usual giant object. My real problem is I need the data in the form that .fetch() gives it to me in. I think it's because the function gets triggered before the data gets a chance to load in, as if I switch out the .fetch() for a .count() it returns 0.

Is there any way around this or a fix?

Upvotes: 3

Views: 5694

Answers (1)

bigmadwolf
bigmadwolf

Reputation: 3519

Where are you you running that console.log?

There are a couple fundementals here that I believe you may have glossed over.

1 Pub / Sub

This is how we get data from the server, when we subscribe to a publication i becomes active and begins to send data, this is neither instant or synchronous, (think of it more like turning on a hose pipe), so when you run your console.log, you may not yet have the data on the client.

2 Reactive contexts

One of the fundamental aspects to building anything in meteor is its reactivity. and it helps to start thinking in terms of reactive and non reactive contexts. A reactive context is one that re-runs each time the data it depends on changes. Using an autorun (Tracker.autorun or this.autorun insdie a template lifecycle callback) or a template helper are good examples. By placing it in a template helper it will re-run when the data is available.

Template.Whatever.helpers({
    items: function() {
        // ...do your find here.....
    }
});

As items is a reactive context, depending on the collection data, it re-run when that changes, giving you access to the data when the client has them.

3 Retrieving Non Reactive Data

Alternatively it is also possible to retrieve data non-reactively by using Meteor.call with a meteor method, and then doing something with the result, in the callback to the Meteor.call. Depending on what you're doing, Meteor.wrapAsync may also be your friend here.

a simple example (out of my head, untested) :

// on the server
Meteor.methods({
    gimmeStuff: function() {
        return "here is your stuff kind sir!";
    }
});

// on the client
Meteor.call('gimmeStuff', function(err, result) {
    if (err || !result) {
       console.log("there was an error or no result!");
       return false;
    }

    console.log(result);
    return result;
});

4 Its Unlikely that you actually need ithe .fetch()

  • If you're working with this in a template, you don't need a fetch.
  • If you want this to be non-reactive you don't need a fetch
  • As one of the commenters mentioned, a cursor is just a wrapper around that array, giving you convenient methods, and reactivity.

5 Go Back to the Begining

If you haven't already, I would highly recommend working through the tutorial on the meteor site carefully and thoroughly, as it covers all of the essentials you'll need to solve far more challenging problems than this, as well as, by way of example, teach you all of the fundamental mechanics to build great apps with Meteor.

Upvotes: 6

Related Questions