8

私はmongoose.jsを使用してmongodbへのクエリを実行していますが、私の問題はmongoose.jsに固有のものではないと思います。

コレクションにレコードが1つしかないとします。

var album = new Album({
    tracks: [{
        title: 'track0',
        language: 'en',

    },{
        title: 'track1',
        language: 'en',
    },{
        title: 'track2',
        language: 'es',
    }]
})

言語フィールドが「en」に等しいすべてのトラックを選択したいので、2つのバリエーションを試しました。

Album.find({'tracks.language':'en'}, {'tracks.$': 1}, function(err, albums){

$ elemMatchプロジェクションで同じものに関連付けられています:

Album.find({}, {tracks: {$elemMatch: {'language': 'en'}}}, function(err, albums){

どちらの場合でも、同じ結果が得られます。

{tracks:[{title: 'track0', language: 'en'}]}

選択したalbum.tracksには、タイトルが「track0」のトラック要素が1つだけ含まれています(ただし、「track0」と「track1」の両方が必要です)。

 {tracks:[{title: 'track0', language: 'en'}, {title: 'track1', language: 'en'}]}

私は何が間違っているのですか?

4

1 に答える 1

17

@JohnnyHKがすでに述べたように、両方とも最初の一致のみを返すため、これを実現するには集約フレームワークを使用する必要があり$ます$elemMatch

方法は次のとおりです。

db.Album.aggregate(
    // This is optional. It might make your query faster if you have
    // many albums that don't have any English tracks. Take a larger 
    // collection and measure the difference. YMMV.
    { $match: {tracks: {$elemMatch: {'language': 'en'}} } },

    // This will create an 'intermediate' document for each track
    { $unwind : "$tracks" },

    // Now filter out the documents that don't contain an English track
    // Note: at this point, documents' 'tracks' element is not an array
    { $match: { "tracks.language" : "en" } },

    // Re-group so the output documents have the same structure, ie.
    // make tracks a subdocument / array again
    { $group : { _id : "$_id", tracks : { $addToSet : "$tracks" } }} 
);

最初の式のみを使用してその集計クエリを試してから、式を1行ずつ追加して、出力がどのように変更されるかを確認することをお勧めします。を使用し$unwindて後で再マージされる中間ドキュメントを作成する方法を理解することは特に重要です。$group$addToSet

結果:

> db.Album.aggregate(
     { $match: {tracks: {$elemMatch: {'language': 'en'}} } }, 
     { $unwind : "$tracks" },
     { $match: { "tracks.language" : "en" } },
     { $group : { _id : "$_id", tracks : { $addToSet : "$tracks" } }}  );
{
    "result" : [
            {
                    "_id" : ObjectId("514217b1c99766f4d210c20b"),
                    "tracks" : [
                            {
                                    "title" : "track1",
                                    "language" : "en"
                            },
                            {
                                    "title" : "track0",
                                    "language" : "en"
                            }
                    ]
            }
    ],
    "ok" : 1
}
于 2013-03-14T19:24:33.790 に答える