sql >> データベース >  >> NoSQL >> MongoDB

集計を使用して、mongoDBで各グループを制限および並べ替えます

    ここでの最善のオプションは、「国」ごとに個別のクエリを実行し(理想的には並列で)、結合された結果を返すことです。クエリは非常に単純で、評価値に並べ替えを適用した後に上位2つの値を返すだけで、完全な結果を得るために複数のクエリを実行する必要がある場合でも、非常に高速に実行されます。

    集約フレームワークは、現在および近い将来でさえ、これに適していません。問題は、グループ化の結果を何らかの方法で「制限」するような演算子がないことです。したがって、これを行うには、基本的に$pushする必要があります すべてのコンテンツを配列に入れ、そこから「上位n」の値を抽出します。

    これを行うために必要な現在の操作はかなりひどいものであり、主要な問題は、ほとんどの実際のデータソースでドキュメントあたり16MBのBSON制限を超える可能性があることです。

    nもあります あなたが今それをしなければならない方法のためにこれに複雑さ。ただし、2つの項目でデモンストレーションするだけです:

    db.collection.aggregate([
        // Sort content by country and rating
        { "$sort": { "Country": 1, "rating": -1 } },
    
        // Group by country and push all items, keeping first result
        { "$group": {
            "_id": "$Country",
            "results": {
                "$push": {
                    "name": "$name", 
                    "rating": "$rating",
                    "id": "$id"
                }
            },
            "first": { 
                "$first": {
                    "name": "$name", 
                    "rating": "$rating",
                    "id": "$id"
                }
            }
        }},
    
        // Unwind the array
        { "$unwind": "results" },
    
        // Remove the seen result from the array
        { "$redact": {
            "$cond": {
                "if": { "$eq": [ "$results.id", "$first.id" ] },
                "then": "$$PRUNE",
                "else": "$$KEEP"
            }
        }},
    
        // Group to return the second result which is now first on stack
        { "$group": {
            "_id": "$_id",
            "first": { "$first": "$first" },
            "second": { 
                "$first": {
                    "name": "$results.name", 
                    "rating": "$results.rating",
                    "id": "$results.id"
                }
            }
        }},
    
        // Optionally put these in an array format
        { "$project": {
            "results": { 
                "$map": {
                    "input": ["A","B"],
                    "as": "el",
                    "in": {
                        "$cond": {
                            "if": { "$eq": [ "$$el", "A" ] },
                            "then": "$first",
                            "else": "$second"
                        }
                    }
                }
            }
        }}
    ])
    

    それは結果をもたらしますが、それは素晴らしいアプローチではなく、より高い制限の反復で、またはグループ化がおそらくn未満である場合でも、はるかに複雑になります 場合によっては結果が返されます。

    執筆時点での現在の開発シリーズ(3.1.x)には、$sliceがあります。 これをもう少し単純にするが、それでも同じ「サイズ」の落とし穴がある演算子:

    db.collection.aggregate([
        // Sort content by country and rating
        { "$sort": { "Country": 1, "rating": -1 } },
    
        // Group by country and push all items, keeping first result
        { "$group": {
            "_id": "$Country",
            "results": {
                "$push": {
                    "name": "$name", 
                    "rating": "$rating",
                    "id": "$id"
                }
            }
        }},
        { "$project": {
            "results": { "$slice": [ "$results", 2 ] }
        }}
    ])
    

    ただし、基本的には、集約フレームワークが$pushによって生成されるアイテムの数を「制限」する方法ができるまでです。 または同様のグループ化「制限」演算子の場合、集約フレームワークはこのタイプの問題に対して実際には最適なソリューションではありません。

    このような単純なクエリ:

    db.collection.find({ "Country": "USA" }).sort({ "rating": -1 }).limit(1)
    

    個別の国ごとに実行し、理想的にはスレッドのイベントループによる並列処理で、結果を組み合わせて、現時点で最適なアプローチを作成します。それらは必要なものだけをフェッチします。これは、集約フレームワークがそのようなグループ化ではまだ処理できない大きな問題です。

    したがって、この「結合されたクエリ結果」を、選択した言語に最適な方法で実行するためのサポートを探してください。これは、集約フレームワークでこれをスローするよりもはるかに複雑でなく、パフォーマンスがはるかに高くなります。




    1. pymongoでインデックスを作成するにはどうすればよいですか

    2. オブジェクトフィールドの順序を変更するmongodbupdate

    3. DynamoDBとMongoDBNoSQL

    4. forEachはmongodbのすべてのコレクションを反復処理しません