1

Currently I have this query:

Post.find().populate([
    {
        path: 'page',
        populate: {
            path: 'url',
            populate: {
                path: 'i18n',
                match: {
                    locale: 'es_ES'
                }
            }
        }
    }
]);

as result, I get:

{
    "title": "Title Post",
    "page": {
        "title": "Title Page",
        "url": [
            {
                "url": "/english",
                "i18n": null
            },
            {
                "url": "/spanish",
                "i18n": {
                    "name": "Spanish",
                    "iso": "es",
                    "locale": "es_ES",
                }
            }
        ]
    }
}

and url is filtered after query:

let url = posts.page.url.filter(value => {
    return value.i18n;
});

I want to load only url relations with i18n.locale = es_ES condition but I don't know how to do it. Wanted result:

{
    "title": "Title Post",
    "page": {
        "title": "Title Page",
        "url": [
            {
                "url": "/spanish",
                "i18n": {
                    "name": "Spanish",
                    "iso": "es",
                    "locale": "es_ES",
                }
            }
        ]
    }
}

I have tried:

Post.find().populate([
    {
        path: 'page',
        populate: {
            path: 'url',
            match: {
                'i18n.locale': 'es_ES'
            }
        }
    }
]);

But is not a valid filter.

Models:

module.exports = mongoose.model('i18n', new Schema({
    name: String,
    iso: String,
    locale: String
}));

module.exports = mongoose.model('page', new Schema({
    title: Object,
    url: [{
        type: Schema.Types.ObjectId,
        ref: 'url'
    }]
));

module.exports = mongoose.model('post', new Schema({
    title: Object,
    page: {
        type: Schema.Types.ObjectId,
        ref: 'page'
    }
}));

module.exports = mongoose.model('url', new Schema({
    url: String,
    i18n: {
        type: Schema.Types.ObjectId,
        ref: 'i18n'
    }
}));

I'm using MongoDB server version 3.6.6 and mongoose 5.2.6.

Thanks!

Ashh
  • 44,693
  • 14
  • 105
  • 132
Lito
  • 1,262
  • 2
  • 17
  • 25

1 Answers1

1

You can try below aggregation in mongodb 3.6

Post.aggregate([
  { "$lookup": {
    "from": Page.collection.name,
    "let": { "page": "$page" },
    "pipeline": [
       { "$match": { "$expr": { "$eq": [ "$_id", "$$page" ] } } },
       { "$lookup": {
         "from": Url.collection.name,
         "let": { "url": "$url" },
         "pipeline": [
           { "$match": { "$expr": { "$in": [ "$_id", "$$url" ] } } },
           { "$lookup": {
             "from": i18n.collection.name,
             "let": { "i18n": "$i18n" },
             "pipeline": [
               { "$match": { "$expr": { "$eq": [ "$_id", "$$i18n" ] } } }
             ],
             "as": "i18n"
           }},
           { "$addFields": { 
             "i18n": { "$arrayElemAt": [ "$i18n", 0 ] }
           }}
         ],
         "as": "url"
       }}
     ],
     "as": "page"
  }},
  { "$unwind": "$page" }
])
Ashh
  • 44,693
  • 14
  • 105
  • 132
  • Thanks a lot for your contribution, but is too complicated to understand to me on future. I'm mongodb newbie and need to understand before to apply :) Anyway, thanks. – Lito Aug 01 '18 at 17:13
  • 1
    Don't worry It looks complicated but you will get it after some time... If you need long-winded explanation then you can go through this https://stackoverflow.com/questions/49953780/lookup-multiple-levels-without-unwind – Ashh Aug 01 '18 at 17:17