我是mongo的新手,并使用 mongodb聚合框架进行查询。我需要检索一些满足特定条件的记录(包括分页+排序),并获得记录的总计数。
现在,我执行后续步骤: 1.创建$ match运算符: {“$ match”:{“year”:“2012”,“author.authorName”:{“$ regex”:“au”,“$ options”:“i”} }} 2.添加了排序和* {“$ sort”:{“some_field”: - 1}},{“$ limit”:10},{“$ skip”:0} *
查询后我收到了预期的结果:10个包含所有字段的文件。
对于分页,我需要知道满足这些条件的记录总数。在我的情况下25。
我使用下一个查询来计算:{ "$match" : { "year" : "2012" , "author.authorName" : { "$regex" : "au" , "$options" : "i"}}} , { "$group" : { "_id" : "$all" , "reviewsCount" : { "$sum" : 1}}} , { "$sort" : { "some_field" : -1}} , { "$limit" : 10} , { "$skip" : 0}
但我不想执行两个单独的查询:一个用于检索文档,第二个用于满足特定条件的记录总数。
我想在一个单个查询中执行此操作,并以下一格式获取结果:
{
"result" : [
{
"my_documets": [
{
"_id" : ObjectId("512f1f47a411dc06281d98c0"),
"author" : {
"authorName" : "author name1",
"email" : "email1@email.com"
}
},
{
"_id" : ObjectId("512f1f47a411dc06281d98c0"),
"author" : {
"authorName" : "author name2",
"email" : "email2@email.com"
}
}, .......
],
"total" : 25
}
],
"ok" : 1
}
我尝试修改群组运营商:{ "$group" : { "_id" : "$all" , "author" : "$author" "reviewsCount" : { "$sum" : 1}}}
但在这种情况下,我得到:“异常:组聚合字段'author'必须定义为对象内的表达式”。如果在_id中添加所有字段,则reviewsCount始终= 1,因为所有记录都不同。
没有人知道如何在单个查询中实现它?也许mongodb有这个案例的一些功能或操作符?使用两个单独的查询的实现降低了查询数千或数百万条记录的性能。在我的应用程序中,这是非常关键的性能问题。
我整天都在研究这个问题并且找不到解决方案,所以我想转向stackoverflow社区。 p>
感谢。
答案 0 :(得分:2)
好的,我有一个例子,但我认为这真的很疯狂查询,我只是为了好玩,但如果这个例子比2个查询快,请在评论中告诉我们。
对于这个问题,我创建了名为“so”的集合,并在此集合中添加了25个这样的文档:
{
"_id" : ObjectId("512fa86cd99d0adda2a744cd"),
"authorName" : "author name1",
"email" : "email1@email.com",
"c" : 1
}
我的查询使用聚合框架:
db.so.aggregate([
{ $group:
{
_id: 1,
collection: { $push : { "_id": "$_id", "authorName": "$authorName", "email": "$email", "c": "$c" } },
count: { $sum: 1 }
}
},
{ $unwind:
"$collection"
},
{ $project:
{ "_id": "$collection._id", "authorName": "$collection.authorName", "email": "$collection.email", "c": "$collection.c", "count": "$count" }
},
{ $match:
{ c: { $lte: 10 } }
},
{ $sort :
{ c: -1 }
},
{ $skip:
2
},
{ $limit:
3
},
{ $group:
{
_id: "$count",
my_documets: {
$push: {"_id": "$_id", "authorName":"$authorName", "email":"$email", "c":"$c" }
}
}
},
{ $project:
{ "_id": 0, "my_documets": "$my_documets", "total": "$_id" }
}
])
此查询的结果:
{
"result" : [
{
"my_documets" : [
{
"_id" : ObjectId("512fa900d99d0adda2a744d4"),
"authorName" : "author name8",
"email" : "email8@email.com",
"c" : 8
},
{
"_id" : ObjectId("512fa900d99d0adda2a744d3"),
"authorName" : "author name7",
"email" : "email7@email.com",
"c" : 7
},
{
"_id" : ObjectId("512fa900d99d0adda2a744d2"),
"authorName" : "author name6",
"email" : "email6@email.com",
"c" : 6
}
],
"total" : 25
}
],
"ok" : 1
}
最后,我认为对于大集合2查询(首先是数据,第二个是计数)工作得更快。例如,您可以像这样计算集合的总数:
db.so.count()
或者像这样:
db.so.find({},{_id:1}).sort({_id:-1}).count()
我在第一个例子中并不完全确定,但在第二个例子中我们只使用光标,这意味着更高的速度:
db.so.find({},{_id:1}).sort({_id:-1}).explain()
{
"cursor" : "BtreeCursor _id_ reverse",
"isMultiKey" : false,
"n" : 25,
"nscannedObjects" : 25,
"nscanned" : 25,
"nscannedObjectsAllPlans" : 25,
"nscannedAllPlans" : 25,
"scanAndOrder" : false,
!!!!!>>> "indexOnly" : true, <<<!!!!!
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
...
}
答案 1 :(得分:0)
为了完整性(完整讨论在MongoDB Google Groups上),这里是您想要的聚合:
db.collection.aggregate(db.docs.aggregate( [
{
"$match" : {
"year" : "2012"
}
},
{
"$group" : {
"_id" : null,
"my_documents" : {
"$push" : {
"_id" : "$_id",
"year" : "$year",
"author" : "$author"
}
},
"reviewsCount" : {
"$sum" : 1
}
}
},
{
"$project" : {
"_id" : 0,
"my_documents" : 1,
"total" : "$reviewsCount"
}
}
] )
顺便说一句,这里不需要聚合框架 - 你可以只使用常规查找。您可以从游标中获取count()而无需重新查询。
答案 2 :(得分:0)
您可以尝试在聚合管道中使用$ facet作为
db.name.aggregate([
{$match:{your match criteria}},
{$facet: {
data: [{$sort: sort},{$skip:skip},{$limit: limit}],
count:[{$group: {_id: null, count: {$sum: 1}}}]
}}
])
在数据中,您将获得带有分页的列表,在count中,count变量将具有匹配文档的总数。