【问题标题】:Publish/subscribe Meteor returns a whole Collection发布/订阅 Meteor 返回整个 Collection
【发布时间】:2016-01-20 04:54:46
【问题描述】:

我正在为我的 Meteor 应用实现发布/订阅架构。我还没有删除autopublish。我使用 React 和 kadira:flow-routerkadira:react-layout。它工作正常。

这是我的发布代码(/lib/publications.js 虽然我也尝试过使用/server/publications.js,但没有变化):

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

    Meteor.publish("game", function(gameId) {
        return Games.find({_id: gameId});
    });

    Meteor.publish("messages", function(gameId) {
        return Messages.find({gameId: gameId}, {sort: {createdAt: -1}});
    });
}

当然,如果我在/server 中使用它,我不会添加if 语句。我像这样(/lib/routing.js)在路由器中订阅这些出版物:

user.route('/game/:id', {
    name: 'game',
    subscriptions: function(params, queryParams) {
        this.register('messages', Meteor.subscribe('messages', params.id));
    },
// ...
});

然后我像这样 (/client/components/pages/game_page.jsx) 在 React 组件中获取数据:

// ...
mixins: [ReactMeteorData],
getMeteorData: function() {
    return {
        messages: Messages.find({}).fetch()
    }
},
// ...

我没有得到所有 gameId 等于传递参数的消息,而是得到来自所有游戏的所有消息。如果我删除发布/订阅并只要求这样的数据:

// ...
mixins: [ReactMeteorData],
getMeteorData: function() {
    return {
        messages: Messages.find({gameId: gameId}, {sort: {createdAt: -1}}).fetch()
    }
},
// ...

它工作得很好。知道为什么吗?我想我错过了一些东西:关于发布/订阅本身或关于在路由器中使用订阅。

【问题讨论】:

  • gameId 设置在哪里?我怀疑它最初是undefined,因此流星订阅了整个集合。由于它永远不会再取消订阅,即使稍后,响应式地再次运行相同的订阅,您也永远不会丢失这些集合条目。
  • 取自路线。 /game/:id 并作为 params.id 传递给订阅。如果我在 this.register(...) 之前 console.log(params.id) 它会正确返回 id。

标签: javascript mongodb meteor reactjs


【解决方案1】:

您必须删除自动发布包,因为默认情况下它会发布集合中的所有内容。

据我了解,每个订阅都会公开集合中的一些文档,因此,如果您对同一个集合有两个订阅,那么当您查询集合时,您将可以访问两个订阅公开的所有文档,因此它是累积的。

【讨论】:

    【解决方案2】:

    Autopublish 包将所有数据发布到客户端(就像您订阅了对所有集合执行 Collection.find({}) 的发布一样)。这意味着,您的自定义发布/订阅实际上在您的示例中什么都不做,如果您像这样查询数据:

    getMeteorData: function() {
        return {
            messages: Messages.find({}).fetch()
        }
    },
    

    您只会收到所有消息,这是正确的行为。

    无论如何,您应该始终像这样在数据查询中进行显式查询:

    getMeteorData: function() {
        return {
            messages: Messages.find({gameId: gameId}, {sort: {createdAt: -1}}).fetch()
        }
    },
    

    因为如果您碰巧同时有两个不同的消息订阅(出于不同的目的,即一个订阅包含所有详细信息的消息,另一个订阅包含较少详细信息/字段的不同消息),此数据查询Messages.find({}) 将让您合并两个订阅中订阅的文档,这可能不是您所期望的。

    因此,在您的情况下,删除自动发布包,并在数据访问中添加此显式查询 (messages: Messages.find({gameId: gameId}, {sort: {createdAt: -1}}).fetch())。

    【讨论】:

    • 是的。在重写了代码的某些部分以使其更易于管理并且更适合组件之后,我必须同意这是实际的答案。 autopublish 需要删除,find({}) 还不够。 getMeteorData 中的完整 MongoDB 查询是必需的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    • 2017-11-30
    • 2013-11-18
    • 2016-03-07
    • 1970-01-01
    相关资源
    最近更新 更多