对mongoDB中的search结果进行分页

我正在尝试在下面的mongoDB中对我的search结果进行分页

{ "data": [ { "_id": "538037b869a1ca1c1ffc96e3", "jobs": "america movie" }, { "_id": "538037a169a1ca1c1ffc96e0", "jobs": "superman movie" }, { "_id": "538037a769a1ca1c1ffc96e1", "jobs": "spider man movie" }, { "_id": "538037af69a1ca1c1ffc96e2", "jobs": "iron man movie" }, { "_id": "538037c569a1ca1c1ffc96e4", "jobs": "social network movie" } ], "Total_results": 5, "author": "Solomon David" } 

这是由textScore索引和sorting,所以我实施了下面的这些分页

 app.get('/search/:q/limit/:lim/skip/:skip',function(req,res){ var l = parseInt(req.params.lim); var s = parseInt(req.params.skip); db.jobs.aggregate({$match:{$text:{$search:req.params.q}}}, {$sort:{score:{$meta:"textScore"}}},{$skip:s},{$limit:l},function(err,docs){res.send({data:docs,Total_results:docs.length,author:"Solomon David"});}); }); 

但是当我试图像这个本地主机:3000 /search/电影/限制/ 1 /跳过/ 0我限制我的结果1,并跳过没有,所以我必须得到如下结果。

 { "data": [ { "_id": "538037b869a1ca1c1ffc96e3", "jobs": "america movie" } ]} 

但我越来越像这样

 { "data": [ { "_id": "538037a169a1ca1c1ffc96e0", "jobs": "superman movie" } ], "Total_results": 1, "author": "Solomon David" } 

请帮助我,我做错了什么

这里似乎有几件事需要解释,所以我会依次尝试一下。 但是首先要解决的是你正在呈现的文档结构。 数组不会产生你想要的结果,所以这里是一个基本的集合结构,现在称之为“电影”:

 { "_id" : "538037b869a1ca1c1ffc96e3", "jobs" : "america movie", "author" : "Solomon David" } { "_id" : "538037a169a1ca1c1ffc96e0", "jobs" : "superman movie", "author" : "Solomon David" } { "_id" : "538037a769a1ca1c1ffc96e1", "jobs" : "spider man movie", "author" : "Solomon David" } { "_id" : "538037af69a1ca1c1ffc96e2", "jobs" : "iron man movie", "author" : "Solomon David" } { "_id" : "538037c569a1ca1c1ffc96e4", "jobs" : "social network movie", "author" : "Solomon David" } 

因此,所有的项目都在单独的文档中,每个项目都有自己的细节和“作者”键。 现在让我们考虑一下使用聚合的基本文本search语句:

 db.movies.aggregate([ { "$match": { "$text": { "$search": "movie" } }}, { "$sort": { "score": { "$meta": "textScore" } } } ]) 

这将search为所提供的术语创build的“文本”索引,并从该查询返回“textScore”排名的结果。 这里使用的forms是这些阶段的缩写,您可以使用它来实际查看“分数”值:

  { "$project": { "jobs": 1, "author": 1, "score": { "$meta": "textScore" } }}, { "$sort": { "score": 1 }} 

但是样品上产生的结果是这样的:

 { "_id" : "538037a169a1ca1c1ffc96e0", "jobs" : "superman movie", "author" : "Solomon David" } { "_id" : "538037b869a1ca1c1ffc96e3", "jobs" : "america movie", "author" : "Solomon David" } { "_id" : "538037c569a1ca1c1ffc96e4", "jobs" : "social network movie", "author" : "Solomon David" } { "_id" : "538037af69a1ca1c1ffc96e2", "jobs" : "iron man movie", "author" : "Solomon David" } { "_id" : "538037a769a1ca1c1ffc96e1", "jobs" : "spider man movie", "author" : "Solomon David" } 

其实所有的东西都有相同的“textScore”,但这是MongoDB将返回它们的顺序。 除非你提供了一些其他的权重或额外的sorting字段,那么这个顺序不会改变。

这基本上涵盖了文本search的第一部分。 文本search不能修改顺序或过滤包含在文档内的数组的内容,所以这就是文档被分开的原因。

对这些结果进行分页是一个简单的过程,即使$skip$limit不是最有效的方法,但通常在使用“文本search”的时候没有其他select。

你似乎试图达到的目的是在某种程度上产生一些关于你的search的“统计”。 无论如何,存储数组中的项目的文件是不是这样做的方式。 所以首先要看的是一个组合的聚合示例:

 db.movies.aggregate([ { "$match": { "$text": { "$search": "movie" } }}, { "$sort": { "score": { "$meta": "textScore" } } }, { "$group": { "_id": null, "data": { "$push": { "_id": "$_id", "jobs": "$jobs", "author": "$author" } }, "Total_Results": { "$sum": 1 }, "author": { "$push": "$author" } }}, { "$unwind": "$author" }, { "$group": { "_id": "$author", "data": { "$first": "$data" }, "Total_Results": { "$first": "$Total_Results" }, "authorCount": { "$sum": 1 } }}, { "$group": { "_id": null, "data": { "$first": "$data" }, "Total_Results": { "$first": "$Total_Results" }, "Author_Info": { "$push": { "author": "$_id", "count": "$authorCount" } } }}, { "$unwind": "$data" }, { "$skip": 0 }, { "$limit": 2 }, { "$group": { "_id": null, "data": { "$push": "$data" }, "Total_Results": { "$first": "$Total_Results" }, "Author_Info": { "$first": "$Author_Info" } }} ]) 

你在这里看到的很多阶段是,你在“Total_Results”和“Author_Info”中获得关于你的总search结果的一些“统计”,并使用$skip$limit来select两个条目的“页面”返回:

 { "_id" : null, "data" : [ { "_id" : "538037a169a1ca1c1ffc96e0", "jobs" : "superman movie", "author" : "Solomon David" }, { "_id" : "538037b869a1ca1c1ffc96e3", "jobs" : "america movie", "author" : "Solomon David" } ], "Total_Results" : 5, "Author_Info" : [ { "author" : "Solomon David", "count" : 5 } ] } 

这里的问题是,你可以看到,当你有大量的结果时,这将变得非常不切实际。 这里的关键部分是为了获得这些“统计”,您需要使用$group $push所有结果$push送到单个文档的数组中。 对于几百个或更多的结果,这可能是正确的,但是对于成千上万的性能会有明显的下降,更不用说内存资源的使用,以及基本上打破单个文档的16MB BSON限制的可能性。

因此,做所有的聚合并不是最实际的解决scheme,如果你真的需要“统计”,那么你最好的select是把它分成两个查询。 首先是“统计”的总量:

 db.movies.aggregate([ { "$match": { "$text": { "$search": "movie" } }}, { "$group": { "_id": "$author", "count": { "$sum": 1 } }}, { "$group": { "_id": null, "Total_Results": { "$sum": "$count" }, "Author_Info": { "$push": { "author": "$_id", "count": "$count" } } }} ]) 

这是基本上相同的事情,除了这次我们没有存储“数据”的实际search结果,而不是担心分页,因为这是一个logging的结果只是提供统计数据。 它很快就会下降到一个单一的logging,或多或less停留在那里,所以这是一个可扩展的解决scheme。

同样显而易见的是,您不需要为每个“页面”执行此操作,只需要使用初始查询来运行此操作。 “统计”可以很容易地caching,所以你可以检索每个“页面”请求的数据。

现在所要做的就是简单地运行每页查询所需的结果,而不用“统计”,这可以简单地使用。 find()表单:

 db.movies.find( { "$text": { "$search": "movie" } }, { "score": { "$meta": "textScore" } } ).sort({ "score": { "$meta": "textScore" } }).skip(0).limit(2) 

这里的简短教训是,你想从你的search“统计”,做一个单独的步骤实际分页的结果。 对于通用数据库分页来说,这是非常普遍的做法,就像“总体结果”的“统计”一样简单。

除此之外,其他选项是查看MongoDB外部的全文search解决scheme。 这些特性比MongoDB开箱即用的“水中脚趾”更具特色,也可能提供更好的性能解决scheme,用于“分页”大量的结果,超过$skip$limit