【问题标题】:Meteor: Hide parts of a returned documentMeteor:隐藏返回文档的部分内容
【发布时间】:2015-12-28 18:59:21
【问题描述】:

我正在尝试在 Meteor 中构建一个简单的多人纸牌游戏,我有两个玩家有一些纸牌。现在,当我订阅包含玩家及其卡片的游戏集合时,所有浏览器客户端都会获得所有数据,这很糟糕。

我可以轻松创建客户端过滤器,仅显示该用户的那些卡片并隐藏其他卡片,但数据已经在浏览器客户端和任何知道他们在做什么的人只能看到那个数据。编写一个小客户端脚本在页面中一直显示它并不难。

其实我在控制台不到一分钟就找到了,它在 this.Games._collection._docs._map[""] 下,你可以看到两个玩家的所有牌...

我在 Todo App 教程中看到我们可以过滤 要返回的行,这很好。但是,我想知道是否可以过滤返回的部分文档?

所以,我的问题是:有没有办法只向客户端发布屏蔽数据?

我的意思是,例如,集合游戏是这样的:

game: {
  player1: {
    username: "john",
    cards: "S8 HA D9 CQ C8"
  }
  player2: {
    username: "mike",
    cards: "HQ D7 SK H8 S7"
  }
}

“john”的客户应该这样获得:

game: {
  player1: {
    username: "john",
    cards: "S8 HA D9 CQ C8"
  }
  player2: {
    username: "mike",
    cards: "XX XX XX XX XX"
  }
}

而“mike”的客户应该这样理解:

game: {
  player1: {
    username: "john",
    cards: "XX XX XX XX XX"
  }
  player2: {
    username: "mike",
    cards: "HQ D7 SK H8 S7"
  }
}

这样的事情是否可能并且仍然是反应性的

或者我是否需要将我的播放器分成不同的集合,然后过滤由用户名/访问权限返回的那些文档?

但即便如此,我仍然需要掩盖这些牌,因为我仍然需要显示 “其他”玩家手中有多少张牌,而不显示它们是哪些牌..

我猜如果可能的话,这应该是

Meteor.publish("games", function () {
    return Games.find({});
});

但我无法弄清楚要在那里添加什么以使其按描述工作......


编辑:我认为this section of the Meteor documentation 可以帮助我。我将尝试发布 Games 集合的多个版本,一个仅发布每个人都可以查看的数据,例如每个玩家拥有的卡片数量,另一个发布仅在允许用户查看卡片的情况下显示卡片。


编辑 2: 嗯。来自the Meteor documentation 我看到了这个:

// server: publish the rooms collection, minus secret info.
Meteor.publish("rooms", function () {
  return Rooms.find({}, {fields: {secretInfo: 0}});
});

// ... and publish secret info for rooms where the logged-in user
// is an admin. If the client subscribes to both streams, the records
// are merged together into the same documents in the Rooms collection.
Meteor.publish("adminSecretInfo", function () {
  return Rooms.find({admin: this.userId}, {fields: {secretInfo: 1}});
});

所以,我尝试这样做:

Meteor.publish("games", function () {
    return Games.find({}, {
        fields: {
            "player1.cards": 0,
            "player2.cards": 0
        }
    });
});

Meteor.publish("playerCards1", function () {
    return Games.find({ "player1.userId": this.userId }, {
        fields: {
            "player1.cards": 1
        }
    });
});

Meteor.publish("playerCards2", function () {
    return Games.find({ "player2.userId": this.userId }, {
        fields: {
            "player2.cards": 1
        }
    });
});

当然,在客户端上:

Meteor.subscribe("games");
Meteor.subscribe("playerCards1");
Meteor.subscribe("playerCards2");
Games = new Mongo.Collection("games");

但是卡片现在根本没有通过。好像playerCards1playerCards1 发布不起作用...

【问题讨论】:

  • 尝试使用console.log 对发布进行调试。你可能会感到惊讶;)
  • 好吧,它显示了用户 ID,然后未定义游戏文档,因为发布发生在游戏创建之前...但是当我重新启动一个客户端以再次触发它时,它显示游戏文档正确地基于关于搜索条件......所以,我很惊讶查询很好但没有到达客户端:(
  • 根据您之前关于发布的问题,我假设您将subscribe 代码放在集合文件中。这不是一个好习惯。你能把它放在routerTemplate.<your-template-name>.rendered 中吗?
  • 等等,发布/订阅是否只发生一次?这意味着如果客户端订阅时用户不在 player1 中,那么它将永远不会获取数据? :( 废话!
  • 我将订阅添加到呈现卡片的模板中,现在发布方法 console.log 打印了正确的结果,但客户端仍然没有显示它:(

标签: meteor


【解决方案1】:

我已经通过使用reactive-publish 包解决了这个问题:

Meteor.publish("games", function () {
    this.autorun(function (c) {
        var game = Games.findOne({
            $or: [
                { "player1.userId": this.userId },
                { "player2.userId": this.userId }
            ]
        });
        if (game) {
            if (this.userId === game.player1.userId) {
                return Games.find({}, { fields: { "player2.cards": 0 } });
            }
            if (this.userId === game.player1.userId) {
                return Games.find({}, { fields: { "player1.cards": 0 } });
            }
            return Games.find({  // this will return only one game
                $or: [
                    { "player1.userId": this.userId },
                    { "player2.userId": this.userId }
                ]
            }, {
                    fields: {
                        "player1.cards": 0,
                        "player2.cards": 0
                    }
                });
        }
        return Games.find({}, {  // this will all games
            fields: {
                "player1.cards": 0,
                "player2.cards": 0
            }
        });
    });
});

编辑:今天我意识到,如果你有多个游戏正在进行中,这是标准场景,我的第一个解决方案并不好,因为这样在一个游戏中坐在 player1 中的用户将获得所有游戏中的所有 player1 玩家。因此,我更新了解决该问题的正确解决方案的答案。

【讨论】:

    猜你喜欢
    • 2016-10-13
    • 2018-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多