Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用mongoose的Mongo自定义排序策略_Javascript_Node.js_Mongodb_Mongoose_Aggregation Framework - Fatal编程技术网

Javascript 使用mongoose的Mongo自定义排序策略

Javascript 使用mongoose的Mongo自定义排序策略,javascript,node.js,mongodb,mongoose,aggregation-framework,Javascript,Node.js,Mongodb,Mongoose,Aggregation Framework,首先:我使用的是Mongo2.6和Mongoose3.8.8 我有以下模式: var-Link=新模式({ 标题:{type:String,trim:true}, 所有者:{id:{type:Schema.ObjectId},名称:{type:String}, url:{type:String,默认值:“”,trim:true}, stars:{users:[{name:{type:String},{u id:{type:Schema.ObjectId}]}, createdAt:{type:D

首先:我使用的是Mongo2.6和Mongoose3.8.8

我有以下模式:

var-Link=新模式({
标题:{type:String,trim:true},
所有者:{id:{type:Schema.ObjectId},名称:{type:String},
url:{type:String,默认值:“”,trim:true},
stars:{users:[{name:{type:String},{u id:{type:Schema.ObjectId}]},
createdAt:{type:Date,默认值:Date.now}
});
我的收藏已经有50万份文件了

我需要的是使用自定义策略对文档进行排序。我最初的解决方案是使用聚合框架

var today=新日期();
//fx=(今天*今天年)-(DocumentCreatedDay*DocumentCreatedYear)
变量相关性={$subtract:[
{$multiply:[{$dayOfYear:today},{$year:today}]},
{$multiply:[{$dayOfYear:'$createdAt'},{$year:'$createdAt'}]}
]}
var投影={
_id:1,
网址:1,
标题:1,
createdAt:1,
缩略图:1,
星:{$size:'$stars.users'}
排名:{$multiply:[相关性,{$size:'$stars.users'}]}
}
变量排序={
$sort:{排名:1,星级:1}
}
var-page=1;
var limit={$limit:40}
var skip={$skip:(40*(第1页))}
var project={$project:projection}
Link.aggregate([project,sort,limit,skip]).exec(resultCallback);
它可以很好地工作到100k,之后查询变得越来越慢。 我怎样才能做到这一点?
重新设计?
我在做什么


谢谢你的时间

您可以在更新时执行所有这些操作,然后您可以实际索引排名并使用范围查询来实现分页。比使用
$skip
$limit
要好得多,这对大数据来说是个坏消息。您应该能够找到许多源代码,确认跳过和限制分页是一种糟糕的做法

这里唯一需要注意的是,由于不能使用
.update()
类型的语句实际引用另一个字段的现有值,因此必须小心更新时的并发性问题。这需要“滚入”一些自定义锁处理,您可以使用
.findOneAndUpdate()
方法:

Link.findOneAndUpdate(
{“_id”:docId,“locked”:false},
{“锁定”:true},
功能(错误、文档){
如果(doc.locked.true){
//然后更新您的文档
//我只会使用每天的纪元日期差
var相关性=(
(Date.now.valueOf()-(Date.now().valueOf()%1000*60*60*24))
-(doc.createdAt.valueOf()-(doc.createdAt.valueOf()%1000*60*60*24))
);
var update={“$set”:{“locked”:false};
如果(操作添加){
更新[“$push”]={“stars.users”:star};
更新[“$set”][“score”]=relevance*(doc.stars.users.length+1);
}否则{
更新[“$pull”]={“stars.users”:star};
更新[“$set”][“score”]=relevance*(doc.stars.users.length-1);
}
//然后更新
Link.findOneAndUpdate(
{“\u id”:doc.\u id,“locked”:更新,函数(err,newDoc){
//可能检查新的“锁定”是否为假,但是否为真
//那应该没问题
});
}否则{
//某些以间隔重试“n”次的机制
//或无法更新的报告
}
}
)
这里的想法是,为了实际更新,您只能获取“锁定”状态等于
false
的文档,而第一个“更新”操作只是将该值设置为
true
,以便在完成此操作之前,其他操作无法更新文档

根据代码注释,您可能希望尝试几次,而不仅仅是更新失败,因为可能会有另一个操作从数组中进行加减操作

然后,根据当前更新的“模式”,如果要向数组中添加项或从数组中删除项,只需更改要发出的update语句以执行任一操作,并在文档中设置适当的“分数”值

当然,更新会将“锁定”状态设置为
false
,检查当前状态是否为
true
,这是有意义的,尽管此时应该是正常的。但这给了您一些引发异常的空间

这将管理一般的更新情况,但您在整理“排名”顺序时仍然存在问题,因为跳过和限制仍然不是您想要的性能。这可能最好通过定期更新另一个字段来处理,您可以使用该字段来确定“范围”查询,但您可能只想关注一组页面中最“相关”的分数范围,而不是更新整个集合

更新需要定期进行,因为如果您试图更改单个更新中多个文档的“排名”顺序,则会出现并发问题。因此,您需要确保此过程不会与其他此类更新重叠

最后,请注意你的“得分”计算,因为你真正想要的是最新的和“最星”的内容在顶部。目前的计算有一些缺点,如在同一天和0个“明星”,但我会留给你去解决。
这基本上就是您的解决方案所需要做的。尝试使用聚合框架在大型集合上动态执行此操作不会为您的应用程序体验带来良好的性能。因此,这里没有几点提示您可以做些什么来更有效地维护结果的顺序。

您有什么缺点吗考虑将计算的
排名
字段添加到