5

I've been banging my head against the wall for a while now, and I assume I'm missing something simple here.

I'm running this on my Meteor server:

// --- Collections ---
Projects = new Meteor.Collection('projects');
Team = new Meteor.Collection('team');

// --- Only publish user data for users on my team ---
Meteor.publish('team', function() {
    var team = Meteor.users.findOne({_id: this.userId}).profile._team;
    console.log(Meteor.users.find({'profile._team': team}, {fields: {_id: 1, profile: 1}}).fetch());
    return Meteor.users.find({'profile._team': team}, {fields: {_id: 1, profile: 1}});
});

This finds all of the users who are on the same "team" by running a query on all user documents who have the same id in the profile._team property as the currently logged in user. You'll see the console.log(...); in the publish function (on the line before the return statement), and it correctly logs the documents I expect it to in my terminal.

Now I'm running this on my client:

// --- Data ---
Meteor.subscribe('team');
Team = new Meteor.Collection('team');

Template.team.team = function() {
    console.log(Team.findOne());
    return Team.find();
};

However, the console.log(Team.findOne()) always logs undefined, Team.find() always returns an empty array. What am I doing incorrectly that is stopping my documents from reaching the client?

UPDATE: Here's the template code.

<body>
    {{> team}}
</body>

<template name="team">
    <p>TEAM TEMPLATE WORKS</p>
    {{#each team}}
        <p>TEAM EACH WORKS</p>
        <div class="teamMember">
            {{profile.firstName}} {{profile.lastName}}
        </div>
    {{/each}}
</template>

"TEAM EACH WORKS" is never rendered inside the {{#each}} tag, but "TEAM TEMPLATE WORKS" renders as expected when it is placed before the {{#each}} tag.

winduptoy
  • 5,366
  • 11
  • 49
  • 67
  • Strange. Please post your template code. – Xyand May 28 '13 at 17:43
  • Added the template code. – winduptoy May 28 '13 at 19:04
  • It helps to understand that the client generally needs to use the same collection name as the server, but the subscription name can be completely different, and it needs to match the publication name (*not* the collection name on the server). See for details [how Meteor collection, subscriptions and publications work](http://stackoverflow.com/a/21853298/1269037). – Dan Dascalescu Feb 18 '14 at 12:18

2 Answers2

3

Here is the problem:

On the client you refer to collection team:

Team = new Meteor.Collection('team');

However in the server publish function you return a cursor to users:

return Meteor.users.find({'profile._team': team}, {fields: {_id: 1, profile: 1}});

No document of team is ever published. In fact you don't even use Team and Projects in the server code.

Old answer:

Try to remove console.log(teamMates.fetch()); or add teamMates.rewind()

From the docs:

The forEach, map, or fetch methods can only be called once on a cursor. To access the data in a cursor more than once, use rewind to reset the cursor.

Xyand
  • 4,470
  • 4
  • 36
  • 63
  • Ah thanks, I had no idea that cursors needed to be rewound. I've removed the call to `fetch()` but unfortunately it still didn't solve my problem. I've updated my question with the code I'm using now. – winduptoy May 28 '13 at 13:19
  • What I'm trying to do is to show the user a list of other users that are on their "team" by finding all the documents in the `users` collection who have the same `_team` id. I do not want the user to see all of the users in the database. So I've made up a published collection called "Team" that runs a query on the `users` collection and returns the matching documents. The `team` collection is not intended to actually exist on disk. Is this the wrong way to go about it? – winduptoy May 30 '13 at 13:43
  • Thanks for your help. Looks like making a new collection was the wrong way to go about it. I was finally able to solve it using this method: http://stackoverflow.com/a/12635270/371273 – winduptoy May 30 '13 at 14:44
2

With meteor it will take a very short amount of time to subscribe to team. While it does this Team.findOne() will return undefined and Team.find() will give an empty array.

If you wait a second or two the data displayed on the client should match up.

You did place your return Team.find() in a template helper, which is reactive. So as soon as the data arrives on the client the UI should display the updated data as long as you have something in your HTML that uses the {{#each team}} helper

Tarang
  • 75,157
  • 39
  • 215
  • 276
  • I see what you're saying, and it makes sense that it would happen that way, since it's asynchronous, but there is nothing appearing in my template. I've used this to prove that it's not working: `{{#each team}} {{log "It works!"}} {{/each}}`. When I log queries to my `Projects` collection in a template helper, the data is logged just as I expect, so my confusion is what's the difference? Could it be some kind of Meteor user permissions when querying from the users database? I thought I got around that by making my own publish/subscribe functions. – winduptoy May 28 '13 at 13:22