简体   繁体   中英

Meteor database design for hierarchical structure

I'm new to Meteor and Mongo, and I have some basic database design questions.

Let's say I'm making a turn based strategy game like Advance Wars . I'm not sure how to structure my data.

I made a little demo where I did this in my html:

{{#each chars}}
  <div class='char' style={{get_style}}>
      ...
  </div>
{{/each}}

And I have this helper defined on Template.body:

Template.body.helpers({
  chars: function() {
    return Characters.find({});
  },
  ...
})

This works fine when I only have one game running at a time. But I'm not sure how to make this work when I have multiple games running concurrently.

I guess one way to do it would be to have a Games collection. Each of these Games references two or more Players and each Player could have a list of Characters. Each Character could have an x and y position. But then I'm not sure what query I would replace Characters.find({}) with.

I guess it could be something like Game.findOne({game_id: game_id}).players[player_id].characters . But I'm not sure what the performance implications are there. Would Meteor pull down the entire game object every time a character moves? I don't really understand what Meteor is doing under the hood.

I guess another possibility that would require minimal changes would be to do something like Characters.find({game_id: 123, player_id: 1}) . And then I would have all the Characters from all the games in one big collection. It seems a bit strange to me to not have the Characters "encapsulated" under a Game, but maybe this is the way to go.

Actually, now that I've written that out, it seems like the second option makes more sense. And I guess I would define all other internal game objects as separate collections. Is this a good way to go about this?

Let's pretend your collection stores items that look like

{
  _id: String,
  started: Date,
  players: [{
    _id: String,
    name: String,
    characters: [{
      _id: String,
      x: Number,
      y: Number
    }, {
      // ...
    }]
  }, {
    // ...
  }]
}

If you have an _id of a game and you need to get all the players and their characters, you do simply

let gameId = 'whatever';
const games = Games.find({
  _id: gameId
});

After that, in games , you have a cursor that will allow you to iterate over a single element, a game you selected by its ID (which is unique by design).

Then, in your template, you do

<div class="games">
  {{#each games}}
    <h1>{{started}} — game's `started` scalar property.</h1>
    {{#each players}}
      <div class="player" id="{{_id}}">
        <h2 id="{{_id}}">{{name}} — player's name</h2>
        {{#each characters}}
          <h3 id="{{_id}}">{{x}}, {{y}} — coordinates of a character</h3>
        {{/each}}
      </div>
    {{/each}}
  {{/each}}
</div>

Note how _id respects current context.

Another way to do the same is use a plain-object instead of cursor, but your should use it only in cases you guarantee the query result to be a single element:

let gameId = 'whatever';
const game = Games.findOne({
  _id: gameId
});

The template will look a bit different. Since you have a single plain-object, you don't have anything to iterate over. So you can access properties of this object omitting the topmost context and replacing it with a with block:

<div class="game">
  {{#with game}}
    <h1>{{started}} — game's `started` scalar property.</h1>
    {{#each players}}
      <div class="player" id="{{_id}}">
        <h2 id="{{_id}}">{{name}} — player's name</h2>
        {{#each characters}}
          <h3 id="{{_id}}">{{x}}, {{y}} — coordinates of a character</h3>
        {{/each}}
      </div>
    {{/each}}
  {{/with}}
</div>

Please make sure that your template (or either the whole client) is subscribed to the Games collection, and this collection is published on the server and returns the whole field set and doesn't query the data (or it does but you control it).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM