Games collection

A lot of these steps we have covered in part 1, so I won't go into too much explanation.

Firstly let's create the games collection:

both/collections/games.js

Games = new Mongo.Collection('games');

We'll also create a dummy game so we have something to play with:

server/seeds.js

Meteor.startup(function () {
  if (Teams.find().count() === 0) {
    // Create some teams
    [
      {name: "Barcelona"},
      {name: "Real Madrid"},
      {name: "Matt's team"}
    ].forEach(function(team){
      Teams.insert(team);
    });

    // Create a game
    var team1 = Teams.find().fetch()[0];
    var team2 = Teams.find().fetch()[1];

    var game = {
      completed: false,
      createdAt: new Date(),
      teams: [
        {name: team1.name, _id: team1._id, score: 0},
        {name: team2.name, _id: team2._id, score: 0}
      ]
    };

    Games.insert(game);
  }
});

Note that I use Teams.find().fetch(). This is because Teams.find() alone doesn't return an array, but rather an object called a 'cursor'. The Meteor docs describe it well:

"find returns a cursor. It does not immediately access the database or return documents. Cursors provide fetch to return all matching documents, map and forEach to iterate over all matching documents, and observe and observeChanges to register callbacks when the set of matching documents changes."

"Cursors are a reactive data source. On the client, the first time you retrieve a cursor's documents with fetch, map, or forEach inside a reactive computation (eg, a template or autorun), Meteor will register a dependency on the underlying data. Any change to the collection that changes the documents in a cursor will trigger a recomputation. To disable this behavior, pass {reactive: false} as an option to find."

So a cursor is like an open door to a collection in the database. To retrieve the actual documents as JSON you'll need to walk through the door and collect it by calling fetch().

While the code looks correct it's actually missing one thing. Remember in our data design we decided to store an array of game ids on each team? Lets update our seeds to take this into account:

server/seeds.js

Meteor.startup(function () {
  if (Teams.find().count() === 0) {
    // Create some teams
    [
      {
        name: "Barcelona",
        gameIds: []
      },
      {
        name: "Real Madrid",
        gameIds: []
      },
      {
        name: "Matt's team",
        gameIds: []
      }
    ].forEach(function(team){
      Teams.insert(team);
    });

    // Create a game
    var team1 = Teams.find().fetch()[0];
    var team2 = Teams.find().fetch()[1];

    var game = {
      completed: false,
      createdAt: new Date(),
      teams: [
        {name: team1.name, _id: team1._id, score: 0},
        {name: team2.name, _id: team2._id, score: 0}
      ]
    };

    var gameId = Games.insert(game);

    // Add this game to both teams gameIds
    Teams.update({_id: team1._id}, {$addToSet: { gameIds: gameId}});
    Teams.update({_id: team2._id}, {$addToSet: { gameIds: gameId}});
  }
});

The only new concept here is the $addToSet operator. The Mongo docs sum it up best:

"The $addToSet operator adds a value to an array only if the value is not already in the array. If the value is in the array, $addToSet does not modify the array."

Basically whenever you want to do something more fancy than change a simple value like a String, I suggest googling it (eg "mongo add to array unique") before trying to wangle it into $set. Or you can peruse the possible options here. If I hadn't found $addToSet I would've had to write more code to make sure the array had unique values.

Remember to reset your data so the game gets inserted:

meteor reset
meteor