简体   繁体   English

在单个查询中获取文档和它们的总数,包括分页

[英]Gets documents and total count of them in single query include pagination

I'm new in mongo and use mongodb aggregation framework for my queries.我是 mongo 的新手,并使用mongodb 聚合框架进行查询。 I need to retrieve some records which satisfy certain conditions( include pagination+sorting) and also get total count of records.我需要检索一些满足某些条件(包括分页+排序)的记录,并获得记录总数

Now, I perform next steps:现在,我执行以下步骤:

  1. Create $match operator创建$match运算符
    { "$match" : { "year" : "2012" , "author.authorName" : { "$regex" : "au" , "$options" : "i"}}}
  2. Added sorting and pagination添加排序和分页
    { "$sort" : { "some_field" : -1}} , { "$limit" : 10} , { "$skip" : 0}

After querying I receive the expected result: 10 documents with all fields.查询后,我收到了预期的结果:10 个包含所有字段的文档。

For pagination I need to know the total count of records which satisfy these conditions, in my case 25.对于分页,我需要知道满足这些条件的记录总数,在我的例子中是 25。

I use next query to get count : { "$match" : { "year" : "2012" , "author.authorName" : { "$regex" : "au" , "$options" : "i"}}} , { "$group" : { "_id" : "$all" , "reviewsCount" : { "$sum" : 1}}} , { "$sort" : { "some_field" : -1}} , { "$limit" : 10} , { "$skip" : 0}我使用下一个查询来获取计数: { "$match" : { "year" : "2012" , "author.authorName" : { "$regex" : "au" , "$options" : "i"}}} , { "$group" : { "_id" : "$all" , "reviewsCount" : { "$sum" : 1}}} , { "$sort" : { "some_field" : -1}} , { "$limit" : 10} , { "$skip" : 0}

But I don't want to perform two separate queries : one for retrieving documents and second for total counts of records which satisfy certain conditions.但我不想执行两个单独的查询:一个用于检索文档,第二个用于满足特定条件的记录总数。

I want do it in one single query and get result in next format:我想在一个查询中完成并以下一种格式获得结果:

{
        "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
}

I tried modify the group operator : { "$group" : { "_id" : "$all" , "author" : "$author" "reviewsCount" : { "$sum" : 1}}} But in this case I got : " exception: the group aggregate field 'author' must be defined as an expression inside an object ".我尝试修改组运算符: { "$group" : { "_id" : "$all" , "author" : "$author" "reviewsCount" : { "$sum" : 1}}}但在这种情况下我得到:“异常:组聚合字段'作者'必须定义为对象内的表达式”。 If add all fields in _id then reviewsCount always = 1 because all records are different.如果在 _id 中添加所有字段,则 reviewCount 始终 = 1,因为所有记录都不同。

Nobody know how it can be implement in single query ?没有人知道如何在单个查询中实现它? Maybe mongodb has some features or operators for this case?也许 mongodb 在这种情况下有一些功能或运算符? Implementation with using two separate query reduces performance for querying thousand or millions records.使用两个单独查询的实现会降低查询数千或数百万条记录的性能。 In my application it's very critical performance issue.在我的应用程序中,这是非常关键的性能问题。

I've been working on this all day and haven't been able to find a solution, so thought i'd turn to the stackoverflow community.我一整天都在研究这个,但一直找不到解决方案,所以我想我会求助于 stackoverflow 社区。

Thanks.谢谢。

You can try using $facet in the aggregation pipeline as您可以尝试在聚合管道中使用 $facet 作为

db.name.aggregate([
{$match:{your match criteria}},
{$facet: {
       data: [{$sort: sort},{$skip:skip},{$limit: limit}],
       count:[{$group: {_id: null, count: {$sum: 1}}}]
}}
])

In data, you'll get your list with pagination and in the count, count variable will have a total count of matched documents.在数据中,您将获得带分页的列表,在计数中,计数变量将具有匹配文档的总数。

Ok, I have one example, but I think it's really crazy query, I put it only for fun, but if this example faster than 2 query, tell us about it in the comments please.好的,我有一个例子,但我认为这真的是一个疯狂的查询,我只是为了好玩,但是如果这个例子比 2 个查询快,请在评论中告诉我们。

For this question i create collection called "so", and put into this collection 25 documents like this:对于这个问题,我创建了一个名为“so”的集合,并将 25 个文档放入这个集合中,如下所示:

{
    "_id" : ObjectId("512fa86cd99d0adda2a744cd"),
    "authorName" : "author name1",
    "email" : "email1@email.com",
    "c" : 1
}

My query use aggregation framework:我的查询使用聚合框架:

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 for this query:此查询的结果:

{
    "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
}

By the end, I think that for big collection 2 query (first for data, second for count) works faster.最后,我认为对于大集合 2 查询(第一个用于数据,第二个用于计数)工作得更快。 For example, you can count total for collection like this:例如,您可以像这样计算集合的总数:

db.so.count()

or like this:或者像这样:

db.so.find({},{_id:1}).sort({_id:-1}).count()

I don't fully sure in first example, but in second example we use only cursor, which means higher speed:我在第一个例子中不完全确定,但在第二个例子中我们只使用游标,这意味着更高的速度:

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,
    ...
}

For completeness (full discussion was on the MongoDB Google Groups ) here is the aggregation you want:为了完整起见(完整讨论在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"
        }
    }
] )

By the way, you don't need aggregation framework here - you can just use a regular find.顺便说一句,您在这里不需要聚合框架 - 您可以只使用常规查找。 You can get count() from a cursor without having to re-query.您可以从游标中获取 count() ,而无需重新查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM