Question

First off, sorry for being a complete javascript noob, I am more of a PHP guy and am just testing out the meteor framework.

I am trying to loop through a collection of objects and trying to add a property from another collections as so :

Template.host.hosts = function() {
    var hosts = Hosts.find();

    hosts.forEach(function(host) {
        host.lastPing = Pings.findOne({id: host.id}, {sort: {timestamp : -1}});

        // This works fine
        // console.log(host.lastPing.id);
    });

    for (host in hosts) {

        // This results in "TypeError: Cannot read property 'id' of undefined"
        console.log(host.lastPing.id);
    }

    return hosts;
};

I don't understand why the second console.log is not working.

I have tried searching but I don't know if the problem is specific to the way meteor handles collections or the way I should be adding properties to a javascript object or someting completely unrelated (scope etc...)

I have simplified my problem to try to understand what is happening, my real problem is obviously looping in a template as per :

{{#each hosts}}
    {{this.lastPing.id}}
{{/each}}

Thanks

Was it helpful?

Solution

Three things:

  1. MongoDB and Meteor ids are stored in _id rather than id.

  2. In the context of your forEach method, host iterates through the query set returned by Hosts.find(), but it doesn't actually give you access to the documents themselves. Essentially, it's a copy of the information in the MongoDB rather than the document in the database.

    The correct (and only) way to update the actual document is by using the Collection.update method:

    Hosts.update({_id: host._id}, {$set: {lastPing: Pings.findOne({id: host.id}, {sort: {timestamp : -1}}) }});
    

    (note that you can only update by _id on the client which is why that's what I've used here, whereas you can supply any query on the server.)

  3. The hosts object is a cursor rather than an array. This means that when you use for host in hosts, you're actually iterating through the properties of the cursor object (which are inherited from the prototype) rather than an array of hosts, and none of them has an id property. One way to make this work is to fetch the query set and put it into hosts like this:

    var hosts = Hosts.find().fetch();
    

    Alternatively, you can stick with the cursor and use forEach again, although you'll either have to rewind it with hosts.rewind(), or repeat the line above to reset it to the start of the query set.

Hope that's helpful.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top