【问题标题】:Mongodb, aggregate query with $lookupMongodb,使用 $lookup 进行聚合查询
【发布时间】:2017-02-16 03:28:15
【问题描述】:

有两个收藏,标签和人物。

标签模型:

{
  en: String,
  sv: String
}

人物模型:

{
  name: String,
  projects: [
    title: String,
    tags: [
      {
        type: Schema.ObjectId,
        ref: 'tag'
      }
    ]
  ]

}

我希望查询返回人员模型中正在使用的所有标签。所有文件。

有点像

var query = mongoose.model('tag').find({...});

或者我应该以某种方式使用聚合方法吗?

【问题讨论】:

  • 您想要整个应用程序中的所有标签还是特定人的所有标签?因为如果你想列出所有标签而不涉及人,你可以直接在标签集合上查询。
  • 我想要整个应用程序中的标签。所有人的 project.tags 中存在的所有标签。

标签: mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

对于任何特定的个人文档,您可以使用populate() 函数,如

var query = mongoose.model("person").find({ "name": "foo" }).populate("projects.tags");

例如,如果您想搜索任何带有“MongoDB”或“Node JS”标签的人,您可以在populate() 函数重载中包含查询选项:

var query = mongoose.model("person").find({ "name": "foo" }).populate({
    "path": "projects.tags",
    "match": { "en": { "$in": ["MongoDB", "Node JS"] } }
});

如果您希望所有人都存在"project.tags" 中的所有标签,那么聚合框架就是您要走的路。考虑在人员集合上运行此管道并使用 $lookup 运算符对标签集合进行左连接:

mongoose.model('person').aggregate([
    { "$unwind": "$projects" },
    { "$unwind": "$projects.tags" },
    {
        "$lookup": {
            "from": "tags",
            "localField": "projects.tags",
            "foreignField": "_id",
            "as": "resultingTagsArray"
        }
    },
    { "$unwind": "$resultingTagsArray" },
    {
        "$group": {
            "_id": null,
            "allTags": { "$addToSet": "$resultingTagsArray" },
            "count": { "$sum": 1 }
        }
    }
 ]).exec(function(err, results){
    console.log(results);
 })

对于任何特定的人,然后应用 $match 管道作为过滤文档的第一步:

mongoose.model('person').aggregate([
    { "$match": { "name": "foo" } },
    { "$unwind": "$projects" },
    { "$unwind": "$projects.tags" },
    {
        "$lookup": {
            "from": "tags",
            "localField": "projects.tags",
            "foreignField": "_id",
            "as": "resultingTagsArray"
        }
    },
    { "$unwind": "$resultingTagsArray" },
    {
        "$group": {
            "_id": null,
            "allTags": { "$addToSet": "$resultingTagsArray" },
            "count": { "$sum": 1 }
        }
    }
 ]).exec(function(err, results){
    console.log(results);
 })

如果您使用不支持 $lookup 运算符的 MongoDB 版本 >= 2.6 或

mongoose.model('person').aggregate([
    { "$unwind": "$projects" },
    { "$unwind": "$projects.tags" },    
    {
        "$group": {
            "_id": null,
            "allTags": { "$addToSet": "$projects.tags" }
        }
    }
 ], function(err, result) {
    mongoose.model('person')
    .populate(result, { "path": "allTags" }, function(err, results) {
        if (err) throw err;
        console.log(JSON.stringify(results, undefined, 4 ));
    });
});

【讨论】:

  • 对不起!我在帖子中犯了一个错误。项目不是一个对象。这是一个数组。我已经更新了这个问题。可以再看一遍吗?
  • 您可以通过为另一个 { "$unwind": "$projects" } 管道添加前缀来解决此问题,如更新的答案中所示。
  • 非常强大的东西。总有一天要学习这个聚合框架。谢谢!
  • 感谢您提出populate() 选项
【解决方案2】:

如果您使用的是 MongoDb 3.2 版,那么您可以使用 $lookup 执行左外连接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    • 2022-01-05
    • 2020-08-10
    • 2021-05-04
    • 2022-07-09
    • 2023-03-09
    相关资源
    最近更新 更多