Meteor:发布中的服务器端排序在页面更改时的行为不符合预期

时间:2014-05-10 18:50:25

标签: sorting meteor publish-subscribe

我有以下设置:我在首页上列出所有项目(发布frontpageItems)并在用户页面上列出所选项目(发布userpageItems)。我在lastactivity字段上对两个页面上的项目进行排序,并在服务器端出版物上进行此操作,而不是在客户端进行,因为我希望首页在加载后是静态的。

  • 每当页面首次加载时,一切都很好,即:1,2,3。
  • 当我从首页导航到用户时,我有2,3的子集,例如
  • 当我导航回首页时,排序为 如下:2,3,1

我认为这是因为meteor缓存了这些项目,但排序顺序在这里肯定是错误的。刷新首页会使排序再次正确。

有什么方法可以解决这个问题吗?即清除页面切换上的订阅例如?我使用iron-router btw在页面加载之前订阅出版物。在客户端上添加客户端排序+被动:false会解决我的问题顺便说一下,但我不能使用这个,因为我需要在订阅限制上进行分页/无限滚动的反应性。

或者,作为一种解决方法,是否可以禁用客户端上的反应性进行排序,但是保持限制?

2 个答案:

答案 0 :(得分:1)

正如大卫在下面提到的,我确实需要对客户进行排序,所以我坚持使用我的出版物尝试了一些不同的指示,以便在客户端上获得某种部分反应。

我最终实现了一个带有observeChanges模式的出版物,并对客户端的lastactivity进行排序。本出版物确保:

  • 最初所有项目都发送给客户(在限制范围内)
  • 每当项目发生变化时,它会删除lastactivity字段并且不会更新,但所有其他属性都会更新并发送给客户
  • 每当添加一个项目时,它会获得一个后来的最后一个活动值,然后是之前的活动变量,因此不会被添加
  • 增加无限滚动的限制继续工作
  • 当客户端刷新时,所有内容都会再次发送到客户端,因为之前的事件已更新

    Meteor.publish('popularPicks', function(limit,beforeLastactivity) {
    
        var init = true;
        var self = this;
    
        if(!beforeLastactivity)
           var beforeLastactivity = new Date().getTime();
    
        if(!limit) {
           var limit = 18;
        }
    
        var query = Picks.find({},{
           limit: limit,
           sort: { lastactivity: -1 }    
        });
    
        var handle = query.observeChanges({
           added: function( id,doc ){ 
              if(init){
                 if(doc.lastactivity < beforeLastactivity)
                    self.added( 'picks', id, doc );
              }     
           },
    
           changed: function( id,fields ){
              if(fields.lastactivity)
                 delete fields.lastactivity;
    
              self.changed( 'picks', id, fields );
           }
        });
    
        var init = false;
    
        self.ready();
    
        self.onStop( function(){
           handle.stop();
        });
    
    });
    

答案 1 :(得分:0)

正如我在this question的答案中所解释的那样,在发布功能中排序不会影响客户端上文档的顺序。但是,由于您使用的是限制,因此在服务器上进行排序确实会影响客户端上的项目。

我已经十几次阅读了你的问题的剩余部分,而且我还不清楚究竟哪些情况需要反应,哪些情况不需要反应。基于短语:&#34;我希望首页在加载后保持静态&#34; ,我建议使用方法(而不是订阅)来加载所需的项目(也许当客户端连接?)并将数据插入会话变量。


根据我们的讨论,如果您可以获得要在页面上显示的一组ID,您可以通过订阅这样的发布函数来反应性地更新它们:

Meteor.publish('itemsWithoutLastActivity', function(ids) {
  check(ids, [String]);
  return Items.find({id: {$in: ids}}, {fields: {lastActivity: 0}});
});

这将在给定数组中发布包含ID的所有项目,但发布lastActivity属性。

但是,从您的初始订阅中收到的文件仍然会被反应 - 在这里它变得非常棘手。如果您保留第一个订阅,则排序顺序将在项目更新时更改。

解决此问题的一种方法是不订阅数据开头。进行方法调用以获取一组有序的ID,然后使用这些ID订阅itemsWithoutLastActivity。您需要提出一种创造性的方式在客户端上订购它们 - 可能只是一个{{#each}},它会迭代ID,每个子模板都会按ID加载所需的项目。