4

私は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}

ただし、 2つの別々のクエリを実行したくありません。1つはドキュメントの取得用で、もう1つは特定の条件を満たすレコードの総数です。

1つのクエリでそれを実行し、次の形式で結果を取得したい:

{
        "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にはこの場合のいくつかの機能や演算子がありますか?2つの個別のクエリを使用して実装すると、数千または数百万のレコードをクエリするパフォーマンスが低下します。私のアプリケーションでは、これは非常に重大なパフォーマンスの問題です。

私はこれに一日中取り組んできましたが、解決策を見つけることができなかったので、stackoverflowコミュニティに目を向けると思いました。

ありがとう。

4

3 に答える 3

2

わかりました、1 つの例がありますが、それは本当にクレイジーなクエリだと思います。私はただの楽しみのためにこれを入れましたが、この例が 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 のクエリ (最初はデータ、2 番目はカウント) の方が高速に動作すると思います。たとえば、次のようにコレクションの合計をカウントできます。

db.so.count()

またはこのように:

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

最初の例ではよくわかりませんが、2 番目の例ではカーソルのみを使用しているため、高速です。

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,
    ...
}
于 2013-02-28T20:28:06.883 に答える
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() を取得できます。

于 2013-02-28T20:48:26.563 に答える