Search code examples
mongodbsecuritymeteorpublishplaying-cards

Meteor - alter data on publish


I am doing a card game in Meteor. Each played game is registered in the collection "Games". A Games' record contain some of the game info as well as some players info and the cards hand of the players (players[i].cards, with values like 4S - 4 of spade, KH - king of heart...). Depending on the cards value, I can display the correct card to the frontend (div.card-KH).

Most of the game data is public but, of course, only the current player's cards must be visible.

One option could be to exclude the cards of the other players at publish time but I still need the number of cards to display the decks (only the remaining cards, hidden) of the other players.

Is there a way to replace the card value of each cards (except user's ones) in players[i].cards to, say, BACK (div.card-BACK) at publish time? Else, what would be the good design pattern to do this in Meteor?


Solution

  • Here is the only solution I found (I don't really like it but it works) :

    Basically, you have to store a temporary document, with the same id but modified data, to another Collection, publish that document from that Collection and finally, from client side, subscribe to that publication. Of course, never make hidden part of the original document available through another publication.

    Meteor.publish('gameWithHiddenCards', function (gameId) {
        var self = this;
    
        //Transform function
        var transform = function(item) {
            for (var i=0; i<item.players.length; i++){
                if ((item.players[i].id != self.userId))
                    for (var j = 0; j < item.players[i].cards.length; j++)
                        item.players[i].cards[j] = 'back';
            return item;
        };
    
        /* 1. Observe changes in game ;
           2. Apply transform function on game data ;
           3. Store it to another Collection. */
        var observer = Games.find({_id: gameId}).observe({
            added: function (document) {
                self.added('secure_games', document._id, transform(document));
            },
            changed: function (newDocument, oldDocument) {
                self.changed('secure_games', newDocument._id, transform(newDocument));
            },
            removed: function (oldDocument) {
                self.removed('secure_games', oldDocument._id);
            }
        });
    
        self.onStop(function () {
            observer.stop();
        });
    
        // Return altered game
        return SecureGames.find({_id: gameId});
    });