如何按发布中的值数组对集合进行排序? (数组不在集合项中)

时间:2016-08-07 10:34:38

标签: mongodb meteor

我有一个集合Cats

{
    "_id" : "rRq76LxsnPfmuh9DD",
    "register_id" : "20gnr3g",
    "name" : "Meow",
    "created_at": ...,
    ...
}

此合集中的每件商品都有唯一的_id和唯一的register_id

我对猫也有RatingLog,现在我想按照评级对猫进行排序。从RatingLog我们可以获得按等级排序的cat register_id数组:

[
    "20gnr3g",
    "3412r23",
    "221n415",
    "Q0g4rEg",
    ...
]

现在我想使用该数组对Cats集合进行排序。请注意,Cats中的所有条目可能未被评分,但应返回所有条目:RatingLog订单中的第一个和created_at字段中的其余项目。

我的出版物代码atm:

Meteor.publish('allCats', function(sortType) {
    if (sortType == 'rating') {
        return Cats.find({}, {sort: { 
            // How to sort by registerIds array???
        }});
    }

    return Cats.find({}, {sort: { created_at: 1 }});
});

所以问题是:如何在Cats数组和register_id字段中对created_at集合进行排序?

1 个答案:

答案 0 :(得分:1)

如果你想反应性地做,你可以用猫存储评级或稍后在Javascript中映射它们。第三个非反应性选项可能是使用带有连接的MongoDB聚合管道(在3.2中添加),但我对此不太熟悉以提供示例。

如果您将评级与猫存储在一起,则变得非常简单:

Meteor.publish('allCats', function (sortType) {
  /**
   * Assuming that Cats contains contents of the form:
   *  {
   *    "_id" : "rRq76LxsnPfmuh9DD",
   *    "register_id" : "20gnr3g",
   *    "name" : "Meow",
   *    "created_at": ...,
   *    "rating": 123,
   *    ...
   *  }
   **/
  if (sortType == 'rating') {
    return Cats.find({}, { sort: { rating: 1 } });
  }

  return Cats.find({}, { sort: { created_at: 1 } });
});

如果您选择将RatingLog分开并希望结果具有反应性,则需要在客户端执行排序;同时发布allCatsallCatRatings

Meteor.publish('allCats', function() {
    return Cats.find({}, {sort: { created_at: 1 }});
});

Meteor.publish('allCatRatings', function() {
    return RatingLog.find();
});

订阅这两个后,检索评级并执行排序:

Template.myTemplate.helpers({
  cats() {
    const sortType = Template.instance().sortType;
    if (sortType === 'rating') {
      return getCatsByRating();
    }
    return getCatsByCreationDate();
  }
});

function getCatsByCreationDate() {
  return Cats.find({}, {sort: { created_at: 1 }});
}

function getCatsByRating() {
  /**
   * Assuming that RatingLog contains contents of the form { _id:  catId, rating: 123 }
   **/
  const ratings = {};
  RatingLog.find().forEach(entry=>ratings[entry._id] = entry.rating);

  const defaultRating = 0;
  return Cats.find().fetch().sort(function (catA, catB) {
    const catARating = ratings[catA._id] || defaultRating;
    const catBRating = ratings[catB._id] || defaultRating;
    return catARating - catBRating;
  });
}