【问题标题】:Meteor Publish + Reactive query objectMeteor Publish + Reactive 查询对象
【发布时间】:2015-08-05 16:59:14
【问题描述】:

考虑以下几点:

在我的客户端上,我构建了一个复杂的过滤器,它保存在一个名为 currentFilter 的自定义反应对象中。

currentFilter.buildQuery() 返回我用来查询 mongodb 数据库的对象。

由于服务端mongodb数据库数据量大,想在服务端过滤数据,只发布给客户端需要的数据。

我的代码如下:

//CLIENT

// file = a.html

<template name="myTemplate">
  {{data}}
</template>

//file = a.js

cbs = new Mongo.Collection('cbsLoc');

Template.myTemplate.helpers({

    data: function () {
        Tracker.autorun(function () {
            Meteor.subscribe('cbsLoc',currentFilter.buildQuery())

        });

        return cbs.find()    // (a)
    }
})

//SERVER

Meteor.publish('cbsLoc', function(filter) {
    return cbs.find(filter)
});

cbs.find() 将返回数据以填充表格。不幸的是,它不起作用。虽然数据确实返回给客户端,但它不会显示在 dom 中。

如果我将(a) 的行更改为cbs.find().fetch(),它可以完美运行(即它确实显示在dom 中)。

非常感谢任何帮助。

【问题讨论】:

  • 您没有为模板提供太多帮助来显示数据。您刚刚给了它一个名为“数据”的对象。那个“数据”对象中有什么?有很多记录还是只有一个? cbs唱片里面有什么?你到底想展示什么?你说它完美地工作但是如果你使用 fetch() - 它将光标变成一个数组。在这种情况下会显示什么?一张桌子?您的意思是您也在数据对象中发送 html 标记吗?抱歉,如果有很多问题,但您实际上并没有提供太多信息。
  • 问题越多越好!我传递给 dom 的数据是一个游标,其记录数 >1,每条记录有 >50 个字段。在应用程序中,{{data}} 实际上是一个 {{> reactiveTable}} 对象(来自响应式表包),它处理 html 表的创建(我试图简化我的示例)。给定在客户端创建的过滤器,我想在 dom 中将返回的过滤光标显示为 HTML 表格。
  • 好的,我问的很明显,但是当您刚刚使用 cbs.find() 时,您的浏览器控制台/开发人员工具中没有消息吗?
  • 控制台中没有错误。当我在浏览器控制台中运行以下命令时:cbs.find() 返回 LocalCollection.Cursor cbs.find().count() 返回 35 cbs.find().fetch() 返回 35 个对象
  • 您不应该从助手开始订阅 - 请参阅 common mistakes。您可能应该将所有这些都移到 template subscription 中。

标签: javascript mongodb meteor


【解决方案1】:

这是我的解决方案。

我将订阅移动到 onCreated() 回调中。我的最后一段代码如下所示:

//CLIENT

// file = a.html

<template name="myTemplate">

    {{#if Template.subscriptionsReady}}
        {{> reactiveTable class="table table-bordered table-hover table-responsive" collection=cbListings settings=settings}}
    {{else}}
        {{>loading}}
    {{/if}}

</template>

//file = a.js

cbs = new Mongo.Collection('cbsLoc');

Template.myTemplate.onCreated(function () {
    var self = this;

    self.autorun(function () {

        self.subscribe('cbs', currFilter.buildQuery());

    });

    self.cbListings = function(){
        return cbs.find();
    }

});

Template.myTemplate.helpers({

    cbListings: function() {

        return Template.instance().cbListings();
    }
});

//SERVER

Meteor.publish('cbsLoc', function(filter) {
    return cbs.find(filter)
});

感谢 David Weldon 和 mwarren 为我指明了正确的方向。

该解决方案基于docs here 以及此blog post

顺便说一句,这只适用于{{#if Template.subscriptionsReady}},如下所示:

{{#if Template.subscriptionsReady}}
    {{> reactiveTable class="table table-bordered table-hover table-responsive" collection=cbListings settings=settings}}
{{else}}
    {{>loading}}
{{/if}}

对我来说,这种模式为什么有效并不明显。我的困惑在于onCreatedhelper 回调之间的关系:

1)

在页面加载时,self.cbListingsnull(这对我来说很有意义)

2)

在此之后,我们让助手创建了cbListings,但它通过Template.instance().cbListings() 代码返回了对自身的引用。

有了以上内容,这里发生了什么?

另外,当Template.instance().cbListings() 尚不存在时,它如何在第一次创建时不引发错误。我知道这一点,因为如果我在onCreated 回调中打印self.cbListings,输出会给我未定义的。但如果我在 self.cbListings 内这样做,我会得到一个输出 = function()(我正在使用萤火虫)。

3)

最后,虽然onCreated 回调只运行一次,Template.subscriptionsReady 正在设法做一些事情,self.cbListings = function(){return cbs.find()}cbListingshelper 创建之后执行。这是怎么回事?

【讨论】:

    【解决方案2】:

    我已将其放入答案中,因为其中有一些代码 - 在评论中难以阅读。

    我唯一能想到的是,在光标的情况下,当模板显示时它还没有准备好,而我似乎记得在 fetch() 的情况下,流星会等到一切都到达。

    尝试一些防御性编码,例如:

    data: function () {
       Tracker.autorun(function () {
           Meteor.subscribe('cbsLoc',currentFilter.buildQuery())
       });
       var cursor = cbs.find();
       if(cursor) 
           return cbs.find()    // (a)
    }
    

    如果这不起作用,那么也许您应该将数据转移到路由器(如果您有 Iron-router),您可以将订阅部分放在 waitOn() 或 subscriptions() 函数中,通常应该是订阅的位置。

    【讨论】:

      猜你喜欢
      • 2015-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多