【问题标题】:Meteor: server side sort in publication not behaving as expected on page changeMeteor:出版物中的服务器端排序在页面更改时未按预期运行
【发布时间】:2014-06-28 09:31:12
【问题描述】:

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

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

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

有没有办法解决这个问题?即,例如清除页面切换上的订阅?我在页面加载之前使用 Iron-router 订阅出版物。在客户端添加客户端排序 + reactive:false 解决了我的问题顺便说一句,但我不能使用它,因为我确实需要对分页/无限滚动的订阅限制做出反应。

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

【问题讨论】:

    标签: sorting meteor publish-subscribe


    【解决方案1】:

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

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

    • 最初所有项目都发送给客户(在课程限制内)
    • 每当更改项目时,它都会删除 lastactivity 字段并且不会更新该字段,但会更新所有其他属性并将其发送给客户端
    • 每当添加一个项目时,它都会获得一个较晚的 lastactivity 值,然后是 beforeLastactivity 变量,因此不会被添加
    • 增加无限滚动的限制继续有效
    • 当客户端刷新时,所有内容都会再次发送到客户端,因为 beforeLastactivity 得到更新

      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();
          });
      
      });
      

    【讨论】:

      【解决方案2】:

      正如我在this question 的回答中所解释的,发布功能中的排序对客户端文档的顺序没有影响。但是,因为您使用的是限制,所以在服务器上进行排序确实会影响 哪些 项将在客户端上。

      我已将您问题的其余部分阅读了十几遍,但我不清楚哪些情况需要反应,哪些不需要。基于这句话:“我希望首页在加载后保持静态”,我建议使用一种方法(而不是订阅)来加载所需的项目(也许当客户端连接时?)并将数据插入到会话变量中。


      根据我们的讨论,如果您可以获得一组您希望出现在页面上的 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 加载所需的项目。

      【讨论】:

      • 嗨大卫,谢谢你到目前为止的回答,我认为发布中的排序确实有效,因为在第一次加载时一切都很好。但情况并非总是如此,这只是一种巧合,最初似乎可以正常工作吗?静态在这里可能有点误导,因为我只希望排序顺序在加载后是静态的,但仍然希望对所示对象的其他一些属性具有反应性。这就是为什么我在考虑一些在 lastactivity 更改时不会更新的自定义发布,但我不确定这将如何影响对象的初始加载。
      • 可能因为 DDP 消息到达客户端的顺序,它们第一次出现排序,但您应该始终自己对它们进行排序。我会在答案中添加一些其他想法,我们可以继续迭代。
      • 您的回答似乎是一个解决方案方向,但是,我今天早上成功地实现了一个带有 observeChanges 的发布,这似乎可以完成这项工作。如果您发现任何不理想或效率低下的内容,请告诉我!再次感谢您的帮助。
      猜你喜欢
      • 1970-01-01
      • 2022-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 2019-11-03
      相关资源
      最近更新 更多