首页 > 解决方案 > $lookup 多个级别

问题描述

目前我有这个查询:

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

结果,我得到:

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

url在查询后过滤:

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

我只想加载有条件的url关系,i18n.locale = es_ES但我不知道该怎么做。想要的结果:

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

我努力了:

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

但不是有效的过滤器。

楷模:

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'
    }
}));

我正在使用 MongoDB 服务器版本 3.6.6 和 mongoose 5.2.6。

谢谢!

标签: mongodbmongoosemongoose-populate

解决方案


您可以在 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" }
])

推荐阅读