私はこの質問が古いことを知っていますが、同様の新しい質問に答えた後、グーグルでそれを見つけました。だから私はこれが同じ治療に値すると思いました。
代わりにaggregateを使用することで、 $whereのパフォーマンスへの影響を回避できます。
db.example.aggregate([
// Use an index, which $where cannot to narrow down
{$match: { "comments.by": "Abe" }},
// De-normalize the Array
{$unwind: "$comments"},
// The order of the array is maintained, so just look for the $last by _id
{$group: { _id: "$_id", comments: {$last: "$comment"} }},
// Match only where that $last comment by `by.Abe`
{$match: { "comments.by": "Abe" }},
// Retain the original _id order
{$sort: { _id: 1 }}
])
そもそも「阿部」のコメントがあったドキュメントを絞り込むことができたので、$whereの周りでリングが鳴るはずです。警告されているように、$ whereはコレクション内のすべてのドキュメントをテストし、使用する必要がある場合でもインデックスを使用しないようにします。
もちろん、ここで説明する手法を使用して元のドキュメントを維持することもできるため、すべてがのように機能しfind()
ます。
これを見つけた人のための単なる思考の糧。
最新のMongoDBリリースの更新
最近のリリースでは、$redact
パイプライン式と$arrayElemAt
(3.2の時点で後者なので、ここでは最小バージョンになります)を追加しました。これを組み合わせることで、論理式で$unwind
ステージを処理せずに配列の最後の要素を検査できます。
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
ここでのロジック$arrayElemAt
は、配列の最後のインデックスを取得する場所と比較して行われます。これは、を介してプロパティ-1
内の値の配列のみに変換されます。これにより、単一の値を必要なパラメーターと比較できます。"by"
$map
"Abe"
$expr
または、MongoDB 3.6以降の使用をもう少し現代的にします:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
これは、配列内の最後の要素を照合するための最もパフォーマンスの高いソリューションであり、実際には$where
、ほとんどの場合、特にここでの使用法に取って代わることが期待されます。