我有以下带有子文档数组的集合:
{
_id:
players: [
{
_id: 1
answer
score:
},
{
_id: 2
answer:
score:
}]
}
我想执行发布功能,以便排除其他玩家的现场回答。即玩家1应该在他的本地最小的这个文档:
{
_id:
players: [
{
_id: 1
answer
score:
},
{
_id: 2
score:
}]
}
我试过这样的事情:
Meteor.publish('game', function (id) {
return Game.find({_id: id}, {players.player_id: 0});
});
但我不知道如何只删除特定玩家的现场答案。
答案 0 :(得分:1)
我讨厌在MongoDB中使用这样的数组。就个人而言,我会使用另一个集合GamePlayers为每个游戏中的每个玩家提供一个文档,例如
Game ({ _id: g1 })
GamePlayers ({ _id: 0, gameId: g1, playerId: p1, answer: x, score: 0 });
GamePlayers ({ _id: 1, gameId: g1, playerId: p2, answer: y, score: 5 });
这会让事情变得更容易。
但实际上在这里回答你的问题是一种方法。我确信有一种更优雅的方式可以做到这一点,但我再次在MongoDB中使用数组,所以我想不到它。
由于meteor发布了有效的observeChanges函数,我们可以做到这一点:
注意:这假设player数组中每个玩家的_id等于用户的Meteor.userId(),如果不是那么你将需要提供playerId作为发布的另一个参数以及gameId和更改作为适当的。
我还假设您的游戏集合被称为“游戏”
Games = new Meteor.Collection("games")
Meteor.publish('game', function(gameId) {
var self = this;
var handle = Games.find(gameId).observeChanges({
added: function(id, fields) {
self.added("games", id, removeSecretPlayerInfo(fields, self.userId));
},
changed: function(id, fields) {
self.changed("games", id, removeSecretPlayerInfo(fields, self.userId));
},
removed: function(id) {
self.removed("games", id);
}
});
self.ready();
self.onStop(function() {
handle.stop();
});
});
//this function takes all the fields that would be sent to the client,
//goes through the player array and if the player's id _id is not equal to
//the id of the user making the subscription we remove the answer from the array
//before sending it to them
var removeSecretPlayerInfo = function(fields, playerId) {
if (fields.players) {
for (var i = 0; i < fields.players.length; i++) {
if (fields.players[i]._id !== playerId)
delete fields.players[i].answer;
}
}
return fields;
}
答案 1 :(得分:0)
查询子字段时需要使用引号。另请注意,要查找的第二个参数位于options
对象上,该对象应具有属性fields
。
return Game.find({_id: id}, {fields: {'players.answer': 0}});