我有一个名为article的集合,我需要对它包含的数组大小返回的对象进行排序。做这个的最好方式是什么? 我想到的是检索整个对象列表并在JS中手动对其进行排序。但是我一次返回文章10,所以每次调用这个API时,它都必须做不必要的排序数组工作。
Article.find({})
.limit(10)
.skip(req.params.page*10)
//Something like using $project to make a new variable called votecount that counts objects in a given array.
.sort({votecount:-1})
.exec(function(err,arts){
articleObj.articles = arts;
if (arts.length<10){
articleObj.reachedEnd = true;
}
res.json(articleObj);
});
我需要计算投票数。这是一个示例对象:
{
"_id" : ObjectId("55f50cfddcf1ad6931fb8dd4"),
"timestamp" : "2015-09-13T00:58:57-5:00",
"url" : "http://www.nytimes.com/2015/09/13/sports/floyd-mayweather-finishes-bout-and-maybe-his-career-with-lopsided-win-over-andre-berto.html",
"abstract" : "Mayweather’s victory by unanimous decision gave him a record of 49-0, the same as the legendary heavyweight Rocky Marciano.",
"title" : "Mayweather Wins Easily in What He Calls Last Bout",
"section" : "Sports",
"comments" : [ ],
"votes" : {
"up" : [
ObjectId("55e5e16934d355d61c471e48")
],
"down" : [ ]
},
"image" : {
"caption" : "Floyd Mayweather Jr. after learning he defeated Andre Berto in a unanimous decision.",
"url" : "http://static01.nyt.com/images/2015/09/14/sports/13fight/13fight-mediumThreeByTwo210.jpg"
},
"__v" : 0
}
答案 0 :(得分:3)
您需要使用.aggregate()
方法,因为所有“sort”参数都必须是文档中的字段,这样您就可以将数组的$size
“投影”到文档中排序:
Article.aggregate(
[
{ "$project": {
"timestamp": 1,
"url": 1,
"abstract": 1,
"title": 1,
"section": 1,
"comments": 1,
"votes": 1,
"image": 1,
"voteCount": {
"$subtract": [
{ "$size": "$votes.up" },
{ "$size": "$votes.down" }
]
}
}},
{ "$sort": { "voteCount": -1 } },
{ "$skip": req.params.page*10 },
{ "$limit": 10 },
],
function(err,results) {
// results here
}
);
当然,这是有代价的,因为您需要在每次迭代时基本上计算大小。因此,更好的做法是在每次更新操作时保持文档中的“计数”,并且更好地使用Bulk Operations以适应所有情况:
var bulk = Atricle.collection.intializeOrderedBulkOp();
// Swap out a downvote where present
bulk.find({
"_id": id,
"votes.up": { "$ne": userId },
"votes.down": userId
}).updateOne({
"$push": { "votes.up": userId },
"$pull": { "votes.down": userId }
"$inc": { "voteCount": 2 }
});
// Add an upvote where not present
bulk.find({
"_id": id,
"votes.up": { "$ne": userId },
"votes.down": { "$ne": userId }
}).updateOne({
"$push": { "votes.up": userId },
"$inc": { "voteCount": 1 }
});
bulk.execute(function(err,response) {
// maybe do something here
});
当然,“downvote”与此过程相反。
这里的要点是,在处理每个投票时,“计数”或“得分”会同时保持更新。这允许进行正常的查询和排序,无需在每次访问数据时进行计算,因为它已经完成。
后一种情况是处理此问题的最佳方式。