2017-06-15 1 views
1

は次のmongoコレクション "イベント" を考えてみましょう:

{ "_id" : ObjectId("512bc95fe835e68f199c8686"), userId: 1, type: "music" eventNum: 1 } 
{ "_id" : ObjectId("512bc962e835e68f199c8687"), userId: 1, type: "music" eventNum: 2 } 
{ "_id" : ObjectId("55f5a192d4bede9ac365b257"), userId: 2, type: "music" eventNum: 3 } 
{ "_id" : ObjectId("55f5a192d4bede9ac365b258"), userId: 2, type: "music" eventNum: 4 } 
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b259"), userId: 1, type: "music" eventNum: 5 } 
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25a"), userId: 1, type: "athletic" eventNum: 6 } 
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25b"), userId: 2, type: "athletic" eventNum: 7 } 

各イベントはuserIdtypeeventNumで作成されます。私はuserId: 1の上位3イベントを見つける必要があります。だから私はこのクエリを実行します。

db.getCollection('events').aggregate([ 
    { 
    "$match": { 
     "userId": 1 
    } 
    }, 
    { 
    "$sort": { "eventNum": 1 } 
    }, 
    { 
    "$limit": 3 
    } 
]) 

データセットを返します(注そこには「運動」のイベントが返されません):今すぐ

{ "_id" : ObjectId("512bc95fe835e68f199c8686"), userId: 1, type: "music" eventNum: 1 } 
{ "_id" : ObjectId("512bc962e835e68f199c8687"), userId: 1, type: "music" eventNum: 2 } 
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b259"), userId: 1, type: "music" eventNum: 5 } 

、しかし、私は、userId: 1のすべての「運動」イベントをしたいです

db.getCollection('events').aggregate([ 
    { 
    "$match": { 
     "userId": 1 
    } 
    }, 
    { 
    "$sort": { "eventTime": 1 } 
    }, 
    { 
    "$limit": 3 
    }, 
    { 
    "$match": { 
     "type": "athletic" 
    } 
    } 
]) 

しかし、このクエリは実際にこのデータを返しますが、トップ3には「運動」のイベントが存在しないので、彼らがトップ3である場合にのみ、私たちは何の書類を返さないために、次のクエリを期待します設定:

{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25a"), userId: 1, type: "athletic" eventNum: 6 } 

誰かがここで何が起こっているのか説明できますか? 2回目の試合後にソート/リミットが起こっているようです。複数のクエリを実行せずにこれを回避する方法はありますか?

+1

これは本当に例を必要としているが、それは一般的にあなたが間違っていることを指します。 '$ match'条件の前に返された文書を表示します。 –

+0

問題を説明するためのより良い例を追加しました。 – M1Reeder

+0

[パイプラインシーケンス最適化](https://docs.mongodb.com/manual/core/aggregation-pipeline-optimization/#pipeline-sequence-optimization)以外は何も考えられていません。私はこの事実のために "背中の背後にある*"ことが起こるのが好きではありません。 –

答えて

1

あなたはthis bugのようなものに当たっているようです。

あなたの正確な例を試しましたが、私はMongoDB 3.4.4上のあなたと同じ奇妙な動作をしていますが、MongoDB 3.0.9では2番目のクエリは何も返しません。

MongoDBをダウングレードしてください。

1

@ramnesが正しいです。これはmongoのバグです3.4.4。しかし、$replaceRootを使用して変数を再割り当てし、その後の一致をトリックしてソート/リミットの後にとどまることで、この問題を回避する方法があります。次のクエリは問題を回避し、期待どおりの結果を返します。

db.getCollection('events').aggregate([ 
    { 
    "$match": { 
     "userId": 1 
    } 
    }, 
    { 
    "$sort": { "eventTime": 1 } 
    }, 
    { 
    "$limit": 3 
    }, 
    { 
    "$replaceRoot": { 
     "newRoot": "$$ROOT" 
    } 
    }, 
    { 
    "$match": { 
     "type": "athletic" 
    } 
    } 
]) 
0

ここに解決策があります。

db.getCollection('events').aggregate([ 
{ 
    "$match": { 
    "$and": [ 
     {"userId": 1}, 
     {"type": "athletic"} 
    ] 
    } 
}, 
{ 
    "$sort": {"eventNum": 1} 
}, 
{ 
    "$limit": 3 
}, 
{ 
    "$group":{ 
    "_id": null, 
    "doc_count": {$sum: 1}, 
    "eventNums": {"$push":"$eventNum"}} 
}, 
{ 
    "$match": { 
     "doc_count": 3 
} 
}, 
]) 

この方法では、イベントが十分でない場合は、上位3つのイベント番号が返されます。

0

変更"$sort"次のコードに:

"$sort": { "eventNum": 1 } != "$sort": { "eventTime": 1 } 
関連する問題