実行時にこのようなものを計算する必要があり、配列からの「フィルタリングされた」コンテンツが並べ替え順序を決定する場合は、 .aggregate()
次のように形状を変更して並べ替え値を決定するには:
db.collection.aggregate([
// Pre-filter the array elements
{ "$project": {
"tags": 1,
"score": {
"$setDifference": [
{ "$map": {
"input": "$tags",
"as": "tag",
"in": {
"$cond": [
{ "$eq": [ "$$el.id", "t1" ] },
"$$el.score",
false
]
}
}},
[false]
]
}
}},
// Unwind to denormalize
{ "$unwind": "$score" },
// Group back the "max" score
{ "$group": {
"_id": "$_id",
"tags": { "$first": "$tags" },
"score": { "$max": "$score" }
}},
// Sort descending by score
{ "$sort": { "score": -1 } }
])
パイプラインの最初の部分を使用して、配列の内容を「事前フィルタリング」し(元のフィールドを保持します)、idが「t1」に等しい「score」の値だけにします。これは、 $ map
を処理することで実行されます。
これは、 $ cond
>
その要素の「スコア」を返すか、 false
を返すかを決定します 。
$ setDifference
操作は、単一要素配列との比較を行います [false]
これにより、 false
が効果的に削除されます $ map
から返された値 。 「セット」として、これは重複するエントリも削除しますが、ここでの並べ替えの目的には、これは良いことです。
配列を縮小し、処理する値に再形成した状態で、 $ unwind
個々の要素として値を処理する次の段階の準備ができています。 $ group
ステージは基本的に $ max
を適用します
「スコア」で、フィルタリングされた結果に含まれる最高値を返します。
次に、 $sortを適用するだけです。コード>
ドキュメントを注文するために決定された値に。当然、これを逆にしたい場合は、 $minを使用してください。
代わりに昇順で並べ替えます。
もちろん、 $ match
を追加します
id
の「t1」値を実際に含むドキュメントだけが本当に必要な場合は最初の段階に進みます タグ内。ただし、その部分は、達成したいフィルタリングされた結果の並べ替えとはほとんど関係がありません。
計算の代わりに、ドキュメントの配列にエントリを書き込むときにすべてを実行することもできます。ちょっと面倒ですが、次のようになります:
db.collection.update(
{ "_id": docId },
{
"$push": { "tags": { "id": "t1", "score": 60 } },
"$max": { "maxt1score": 60 },
"$min": { "mint1score": 60 }
}
)
ここでは、 $ max
update演算子は、新しい値が既存の値より大きい場合、またはプロパティがまだ存在しない場合にのみ、指定されたフィールドの値を設定します。逆の場合は、 $ min
>
、それより少ない場合にのみ、新しい値に置き換えられます。
もちろん、これにはドキュメントにさまざまなプロパティを追加する効果がありますが、最終的には並べ替えが大幅に簡素化されます。
db.collection.find().sort({ "maxt1score": -1 })
また、集計パイプラインを使用して計算するよりもはるかに高速に実行されます。
したがって、設計原則を検討してください。並べ替えの結果をフィルター処理してペアにする必要がある配列の構造化データは、実行時に計算して、並べ替える値を決定することを意味します。 .update()
でドキュメントにプロパティを追加する つまり、これらのプロパティを参照するだけで、結果を直接並べ替えることができます。