Meteor/Mongodb - массивы, поддокументы и перекрывающиеся подписки
Я делаю игру; игроки формируют лиги и делают конкурирующие прогнозы. Лига выглядит так:
{ leagueName: "Premier League",
players:[
{name: "Goodie", secretPrediction: "abc"},
{name: "Baddie", secretPrediction: "def"}
] }
Для каждого игрока мне нужно опубликовать клиенту имена всех игроков в лиге, но только их собственный секретный прогноз. Итак, сверху, если вошел Goodie, документ на мини-монго должен быть:
{ leagueName: "Premier League",
players:[
{name: "Goodie", secretPrediction: "abc"},
{name: "Baddie"}
] }
Для этого у меня есть две публикации - одна, чтобы получить весь документ Лиги, но исключая ВСЕ секретные прогнозы, и одна, чтобы получить поддокумент текущего игрока в массиве игроков, включая ее секретный прогноз. Мои публикации:
// 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"}}}})
Проблема в том, что когда я подписываюсь на обе вышеупомянутые публикации, я не получаю нужный документ - секретный прогноз исключается даже со второй публикацией. (Публикации ведут себя как положено, только когда я подписываюсь на оба.)
Теперь я понимаю из этого ответа, что две публикации должны быть "объединены" на клиенте
Вплоть до уровня полей верхнего уровня, Meteor позаботится о том, чтобы установить объединение среди документов, чтобы подписки могли перекрываться - публиковать функции, которые отправляют различные поля верхнего уровня клиенту, работая бок о бок и на клиенте, документ в коллекция будет объединением двух наборов полей.
Итак, у меня есть два основных вопроса (и хорошо сделано / спасибо, что сделали это так далеко!):
- Не происходит ли объединение документов, потому что я не имею дело с полями верхнего уровня? Это можно обойти?
- Я иду по этому пути совершенно неправильно? Есть ли лучший способ получить результаты, которые я хочу?
2 ответа
Не могли бы вы вместо этого переставить документ данных, чтобы вы могли использовать один запрос, например
{ leagueName: "Premier League",
players:[
{name: "Goodie"},
{name: "Baddie"}
]
playerPredictions:[
{name: "Goodie", secretPrediction: "abc"},
{name: "Baddie", secretPrediction: "def"}
]
}
Таким образом, можно было бы в одном запросе вернуть всех игроков и только playerPrediction для данного человека.
Да, объединение нескольких подписок Meteor работает только с полями верхнего уровня, это упоминается в документации Meteor: Meteor.subscribe
Я не могу сказать, что вы движетесь в неправильном направлении, это действительно зависит от вашей ситуации, какими функциями вы хотите помочь. Говоря только о себе, я бы разделил вышеупомянутую коллекцию на две отдельные коллекции. Поскольку игроки могут присоединиться ко многим лигам, а в лигах может быть много игроков, их отношение много ко многим (nn). Для такого рода отношений мы должны разделить их на две коллекции и использовать ассоциативную таблицу для отражения их отношения
Так что в вашем случае я бы имел:
Коллекция Лиги:
[{
_id: 'league1',
name: 'League 1',
// ...
}]
Коллекция игроков:
[{
_id: 'player1',
name: 'Player 1',
// ...
}]
League2Player коллекция:
[{
_id: 'league1palyer1',
playerId: 'player1',
leagueId: 'league1',
secretPrediction: 'abc',
// ...
}]