Creating mongoose.js object with multiple 'ref' fields. (Or: how to switch to a nosql, event driven mindset)

StackOverflow https://stackoverflow.com/questions/23624944

  •  21-07-2023
  •  | 
  •  

Pregunta

First of all, I'm coming from years of using Django and relational databases, but want to try something new - so this is probably a conceptual problem on my part. I'm just not sure where it is. Hope the question is clear enough, even though I'm not sure what I should be asking...

So. I'm setting up an application that contains Teams, and Matches between these teams.

Here are my models:

var TeamSchema = new Schema({
  name: String,
  code: String
});

TeamSchema.statics = {
  list: function(options, cb) {
    var criteria = options.criteria || {};
    this.find(criteria)
      .exec(cb);
  },
  load: function(id, cb) {
    this.findOne({_id: id})
      .exec(cb);
  },
};

var MatchSchema = new Schema({
  home_team: { type: Schema.ObjectId, ref: 'Team' },
  away_team: { type: Schema.ObjectId, ref: 'Team' },
  datetime: Date,
  slug: String,
  home_score: Number,
  away_score: Number
});

Where I run into problems is when I want to populate these models programmatically. The teams are easy enough:

// Clear old teams, then add default teams
Team.find({}).remove(function() {
  Team.create({
    name: 'Brazil',
    code: 'bra'
  }, {
    name: 'Cameroon',
    code: 'cmr'
  }, {
    name: 'Spain',
    code: 'esp'
  }, {
....

But then I want to create matches, which requires getting the _ids for the teams. In my way of thinking this is pretty easy: Create the Teams, then before creating the Matches fetch the appropriate Teams and assign to variables, and finally create a Match using these variables to populate the home_team and away_team fields.

This of course doesn't work here, since there's no guarantee the Teams have been populated when the Match creating function is called. So I moved that code to the callback of the Team creation code. But still that didn't work, since when the Match is created the Team variables are still not populated. I sort of got this to work by putting the match creation code as a callback to the Team lookup (which itself is a callback to the Team creation code). But that only works for ONE of the Teams, how do I ensure I have both the _ids available before creating a Match?

As I said in the beginning, I feel like I'm thinking about this the wrong way - so I'm not necessarily looking for working code, more for pointers about where I'm going wrong in my thinking.

That said, this is the working code I have for setting one of the teams:

// Clear old teams, then add default teams
Team.find({}).remove(function() {
  Team.create({
    name: 'Brazil',
    code: 'bra'
  }, {
    name: 'Croatia',
    code: 'hrv'
  }, 
  function() {
    console.log('finished populating teams');
    // Clear old matches, then add default matches
    Match.find({}).remove(function() {
      Team.findOne({code: 'bra'}, function(err, obj) {
        if (!err) {
          console.log(obj.code);
          Match.create({
            datetime: "2014-06-01T22:00:00.000Z",
            slug: 'bra-hrv',
            home_team: obj._id
         });
       } else {
         console.log(err);
       }
     });
    });
  });
});

Edit: Found one way around it. Since code is unique to each team, I switched the team _id field to String and removed code. That way I can easily create the Match objects without having to look up the _id - I already know what it is.

Doesn't really solve my underlying problem, but it does get the work done.

¿Fue útil?

Solución

If you use new and save to create your Team docs you'll have immediate access to their _id values because they're assigned client-side:

var brazil = new Team({
    name: 'Brazil',
    code: 'bra'
  });
brazil.save();
var croatia = new Team({
    name: 'Croatia',
    code: 'hrv'
  });
croatia.save();

Match.create({
  datetime: "2014-06-01T22:00:00.000Z",
  slug: 'bra-hrv',
  home_team: brazil._id,
  away_team: croatia._id
});
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top