【问题标题】:Categories not found, Meteor subscription未找到类别, Meteor 订阅
【发布时间】:2015-06-20 02:55:24
【问题描述】:

因此,我希望我的 Meteor 应用程序的 Categories 集合的内容始终可用于整个应用程序。我在某处读到,您可以通过将null 指定为Meteor.publish 函数的第一个参数(而不是名称)来做到这一点。

我使用了以下代码:

// Categories
Meteor.publish(null, function() {
    return Categories.find();
});

当我启动我的应用程序时,我在应用程序启动时收到以下错误(上面的代码段位于<app>/server/publications/global.js):

Exception from sub id undefined ReferenceError: Categories is not defined
  at [object Object].Meteor.publish.Meteor.users.find.fields.username [as _handler] (app/server/publications/global.js:8:12)
  at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1617:1)
  at [object Object]._.extend._runHandler (packages/ddp/livedata_server.js:950:1)
  at [object Object]._.extend._startSubscription (packages/ddp/livedata_server.js:769:1)
  at packages/ddp/livedata_server.js:1437:1

奇怪的是,它这么说,但该出版物似乎运行良好。 Mongol 报告说,Categories 数据在我的整个应用程序中都可用,并且没有其他地方发布该数据,所以它一定来自这个调用。

有什么想法吗?我有点困惑。我应该在返回之前检查子目录中是否存在类别吗?

【问题讨论】:

  • 您在哪里定义类别?
  • 它可能重新运行并在重新运行时找到了类别。

标签: node.js meteor


【解决方案1】:

补充一下 Matt K 所说的内容(因为 cmets 很烂,而且 cmets 中的代码格式确实很糟糕),这是一个可能的代码示例,它创建了一个命名集合并在连接的客户端和服务器之间保持其数据的同步:

/lib/collections.js - 在服务器和客户端上运行

Categories = new Mongo.Collection('categories');

/server/publications.js

Meteor.publish('categories', function() {
    return Categories.find();
});

/lib/router.js - (用于 Iron Router 并告诉所有路径等到my_collection 被订阅后再加载)

Router.configure({
  loadingTemplate: 'loading',
  waitOn: function() {
    return [
      Meteor.subscribe('categories')
    ];
  }
});

现在在 OP 中所做的是在服务器上创建一个未命名的集合,然后将其发布到所有连接的客户端:

http://docs.meteor.com/#/full/meteor_publish

/lib/collections.js

Categories = new Mongo.Collection('categories');

/server/publications

Meteor.publish(null, function() {
    return Categories.find();
});

它所做的只是将它从Categories.find(); 获得的所有这些数据以没有名称的集合的形式发送给客户端。由于它没有名称,因此无法直接判断客户端何时成功订阅它,因为它没有任何东西可供waitOn 寻找,但有一个可能的解决方案..

When is the "null" publish ready?

https://github.com/alanning/meteor-null-publish-test

但总而言之,向客户端发布一个空(未命名)集合是非常愚蠢的,因为您不知道数据何时在每个客户端上可用。如果可以,请避免使用我在本文上半部分描述的标准 pub/sub 模式。

【讨论】:

  • 这似乎是一个不错的解决方案。我不知道我可以在Router.configure 中使用waitOn,并且会这样做。非常感谢。如果我能接受你的两个答案,我会的。我会接受这个,因为它有点建立在另一个之上,并且包含我认为将是我的最终解决方案。
  • 您可以在Router.configure 中执行waitOn(它需要一个订阅数组)`,这会导致所有路由订阅这些发布。您可以在单个路由上执行waitOn,也可以在RouteController 中执行waitOn,这也可以覆盖Router.configure 中的全局订阅
  • 太棒了。我喜欢 Meteor,这个社区非常乐于助人而且很棒。再次感谢您的精彩回答,它非常有用且全面。
【解决方案2】:

在你得到结果之前,Meteor 正在做 3 件事......

  1. 定义变量Categories(大失败)
  2. Categories 获得数据之前返回光标(这是IR 的waitOn 的用处)
  3. 将光标返回到 Categories 并带有数据(眨眼后看到的内容)

您的应用程序的问题是它甚至在知道它是什么之前就试图发布它。然后,一旦发现它是什么,它就会重新发布,一切都很好。这是一个应用程序加载顺序问题。确保您的集合是在客户端和服务器上定义的(通常在名为集合的文件夹中)。然后,确保您的发布功能位于名为 server.xml 的文件夹中。这样做可以保证您的集合脚本在发布脚本之前运行。

解决了这个问题后,你的下一个问题将是防御性编码。仅仅因为您始终订阅 Categories 并不意味着它始终可用,订阅需要时间。

例如,这个:

doc = Categories.findOne();
if (!doc) return;
...
return doc && doc.createdAt;

不是这个:

Categories.findOne().createdAt

同样的逻辑可以应用于发布功能来解决你现在的问题:

return Categories && Categories.find();

但我不建议这样做,因为您可以通过正确排序文档来避免额外的几个 CPU 周期。

【讨论】:

  • 啊,我明白了。我想我有点认为这是一个加载顺序的事情,这是它可以抛出错误并同时工作的唯一方法。非常感谢。
猜你喜欢
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 2016-11-23
  • 2022-08-16
  • 2013-01-18
相关资源
最近更新 更多