1

I'm making a game; players form leagues and make competing predictions. A league looks like this:

{ leagueName: "Premier League", 
players:[ 
         {name: "Goodie", secretPrediction: "abc"}, 
         {name: "Baddie", secretPrediction: "def"} 
        ] }

For each player, I need to publish to the client the names of all the players in the league, but only their own secret prediction. So from above, if Goodie is logged in, the document on mini-mongo should be:

{ leagueName: "Premier League", 
  players:[ 
           {name: "Goodie", secretPrediction: "abc"}, 
           {name: "Baddie"} 
          ] }

To do this, I have two publications - one to get the whole League document but excluding ALL secret predictions, and one to get the current player's subdocument in the players array including her secret prediction. My publications are:

// Publish whole players array excluding secretPrediction
Leagues.find({"players.name": "Goodie"}, {fields: {"players.secretPrediction": 0}})

// Publish the whole Goodie item in the players array and nothing else 
Leagues.find({"players.name": "Goodie"}, {fields: {players: {$elemMatch: {name: "Goodie"}}}})

The problem is that when I subscribe to both the above publications, I don't get the document I want - the secret prediction is excluded even with the second publication. (On their own, the publications behave as expected, it's only when I subscribe to both.)

Now, I understand from this answer that the two publications should be "merged" on the client

Down to the level of top level fields, Meteor takes care to perform a set union among documents, such that subscriptions can overlap - publish functions that ship different top level fields to the client work side by side and on the client, the document in the collection will be the union of the two sets of fields.

So I have two main questions (and well done / thanks for making it this far!):

  1. Is the union of documents not happening because I'm not dealing with top level fields? Is there a way around this?
  2. Am I going about this completely the wrong way? Is there a better way to get the results I want?
Community
  • 1
  • 1
rubie
  • 1,906
  • 2
  • 20
  • 26

2 Answers2

3
  1. Yes, the merging multiple subscriptions of Meteor only works with the top level fields, it is mentioned in the Meteor docs: Meteor.subscribe

  2. I can not say that you are heading the wrong direction, this really depends on your situation, what features you want to help. Only speak of myself, I would decouple the above collection to two separate collections. Because players may join many leagues and leagues may have many players, so their relation is many-to-many (n-n). For this kind of relation, we should split them to two collections and use an associative table to reflect their relation

So in your case, I would have:

League collection:

[{
  _id: 'league1',
  name: 'League 1',
  // ...
}]

Player collection:

[{
  _id: 'player1',
  name: 'Player 1',
  // ...
}]

League2Player collection:

[{
  _id: 'league1palyer1',
  playerId: 'player1',
  leagueId: 'league1',
  secretPrediction: 'abc',
  // ...
}]
kkkkkkk
  • 7,628
  • 2
  • 18
  • 31
  • Good spot in the docs - I didn't see that comment. And - "We hope to lift this restriction in a future release." - hopefully soon... – rubie Dec 01 '16 at 11:08
2

Could you instead rearrange the data document so that you can use a single query e.g.

{ leagueName: "Premier League", 
players:[ 
         {name: "Goodie"}, 
         {name: "Baddie"} 
        ] 
playerPredictions:[ 
         {name: "Goodie", secretPrediction: "abc"}, 
         {name: "Baddie", secretPrediction: "def"} 
        ] 
}

That way it would be possible in a single query to return all the players and only the playerPrediction for the given person.

matt90410
  • 455
  • 4
  • 7
  • Accepting this as the answer because I think it's the simplest and quickest way to get the result I need – rubie Dec 01 '16 at 11:05