经过大量阅读后,我开始更好地处理Meteor的发布/订阅模型。我已经从我的第一个应用程序中删除了自动发布培训轮,虽然我的一切工作正常,但我发现了一个问题。
首次加载应用时,我的发布和订阅挂钩效果很好。我有一个代码块在Tracker.autorun()
块中运行,它进行订阅调用,我能够在订阅句柄上使用ready()
顺序等待来自服务器的数据等。
我的应用程序的一个功能是它允许用户将新文档插入到集合中。更具体地,当用户执行特定动作时,这触发插入。此时,客户端JS运行并且插入MiniMongo完成。反应autorun
块运行,客户端可以看到插入的文档。客户端使用新插入的数据更新DOM,一切都很好。
此外,当我查看服务器端的MongoDB时,我看到插入的文档,这意味着服务器端的JS运行正常。
在这里,它变得奇怪。客户端autorun
块第二次运行(我不确定为什么),这次,客户端不再具有插入的项目。当DOM渲染时,新插入的项目现在消失了。如果我重新加载页面,一切都很好。
之前有没有人见过这种行为?我还注意到服务器端发布调用在页面加载时运行一次,但在插入后它不再运行。这似乎是错误的,因为客户端在插入后如何从服务器获得协调数据(即在Meteor的客户端延迟补偿之后)?
重要的功能(ComponentInstances
是错误的集合):
发布块:
Meteor.publish('allComponentInstances', function (documentId, screenIndex) {
console.log(`documentId: ${documentId} screenIndex: ${screenIndex}`)
const screens = Screens.find({ownerDocumentId: documentId})
const selectedScreen = screens.fetch()[screenIndex]
return ComponentInstances.find({_id: {$in: selectedScreen.allComponentInstanceIds}})
})
autorun
中的订阅块:
// ... a bunch of irrelevant code above
const allComponentInstancesHandle = Meteor.subscribe('allComponentInstances', document._id, 0)
if (allComponentInstancesHandle.ready()) {
isReady = true
screens = Screens.find({ownerDocumentId: document._id}).fetch()
const componentInstanceObjects = ComponentInstances.find().fetch()
allComponentInstances = {}
componentInstanceObjects.map((componentInstance) => {
allComponentInstances[componentInstance._id] = componentInstance
})
}
答案 0 :(得分:1)
这很可能是您从客户端插入文档。而且您还没有正确设置权限规则。从应用中删除autopublish
和insecure
时,除非您在服务器端设置了allow/deny
规则,否则不允许将文档插入/更新/删除。
Meteor有一个很棒的功能叫latency compensation
,它会在数据库中获得实际的写入操作之前尝试模拟数据库操作。当服务器尝试在db中写入时,它会查找allow/deny
个规则。如果权限规则不允许db操作或者无论是什么原因(允许/拒绝或认证)都没有实际写入db,然后服务器数据与客户端数据库同步。
这就是为什么我假设您第一次看到您的文档被插入并在一秒钟内消失。
查看流星文档的这一部分。 http://docs.meteor.com/#/full/allow
答案 1 :(得分:0)
我最终以不同的方式解决了这个问题。我认为,核心问题与接受/拒绝规则无关。事实上,他们的角色对我来说仍然是模糊的。
我现在意识到我在Meteor文档中一直在阅读的内容:发布函数返回游标。如果光标本身没有改变(例如,如果你要传递你想要获取的特定键),那么它就不会真正起到反应数据源的作用,因为集合中的新文档不会使数据发布再次。毕竟,你仍然要求相同的密钥。
前进的方向是提出一个发布光标,准确反映您要检索的被动数据。这听起来很抽象,但在实践中,它意味着确保光标是通用的,而不是特定于您要检索的特定键。