MongoDB: select consistent subset elements

I use mongoose.js to execute requests to mongodb, but I think my problem is not specific to mongoose.js.

Say I have only one entry in the collection:

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

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

I want to select all tracks with a language field equal to 'en', so I tried two options:

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

and attached to the same with the $ elemMatch projection:

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

Anyway, I have the same result:

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

selected album.tracks contain only one track element named "track0" (but there must be both "track0", "track1"):

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

What am I doing wrong?

+5
source share
1 answer

@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" } }} 
);

, , , , . , $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
}
+11

All Articles