是否可以只对一个集合进行一次排序,然后尽管有反应,但仍保持该顺序不变?

Is it possible to sort a collection only once and then keep that order intact despite reactivity?

我有一个评论列表。这些评论有一个名为 "vote" 的属性(用户可以对评论进行投票),它们最初按投票排序(降序,onRender)。

现在,当用户投票时,评论的顺序会被动更新以反映新的投票。

是否有可能以某种方式保持初始排序顺序不变?当 she/he 在页面上时,我想避免将用户与评论自动交换顺序混淆。

请问有什么好的方法可以解决吗?我在考虑渲染页面时可能是一次性排序,或者以某种方式保存顺序,然后在响应式刷新集合时重新应用它。

因为您不关心新评论,只关心新投票,所以我会用 Meteor.call() 按您想要的方式对初始人口进行排序,如@sdybskiy 所述。然后我会为这些评论设置订阅以获得投票数。

在模板的 onCreated() 中,您可以像这样设置订阅:

let voteCursor = Votes.find({commentIds: comments});
    voteCursor.observe({
        added: function(newDocument, oldDocument) {
            // the published vote would have a commentId, so here you
            // would go to your client store for the comments, find the 
            // comment, and increment the count
        },
        removed: function(oldDocument) {
            // same idea here, but process a vote being removed
        }
    });

注意我正在传递从该方法返回的所有评论的 ID,因此发布将只发布这些评论的投票。

您可以使用 reactive: false 选项执行 non-reactive find,例如:

Comments.find({},{sort: {vote: -1}, reactive: false});

如果您想在原始列表之后添加新评论,那么我会呈现两个评论列表,一个接一个。首先呈现现有评论的排序列表,然后以创建顺序响应地呈现在初始呈现时间之后创建的评论列表。第二个列表最初是空的,根本不会呈现,但最终新评论会出现在那里,并带有自己的投票数。

现在,由于上面的光标是 non-reactive,我们如何在不改变顺序的情况下让投票计数反应性地更新?答案:(在 Blaze 的情况下)使用反应式助手!

Template.myTemplate.helpers({
  currentVote(){
    return Comments.findOne(this._id).vote;
  }
});

从性能角度来看,这实际上是出奇的便宜。

您可以使用函数对您的 Minimongo 查询进行排序。所以像:

const initialVotes = new Map();
Comments.find({}, {sort: (a, b) => {
  if (!initialVotes.has(a._id)) initialVotes.set(a._id, a.votes);
  if (!initialVotes.has(b._id)) initialVotes.set(b._id, b.votes);

  return initialVotes.get(b._id) - initialVotes.get(a._id);
});

这将使评论按初始投票排序。如果有任何其他变化(比如用户编辑评论),那将反应性传播,如果有新评论,它将反应性地添加。但如果票数改变,顺序不会改变(但可能呈现的票数仍会更新)。