繁体   English   中英

基于多个联接的MongoDB查询

[英]MongoDB query based on multiple joins

关于联接和MongoDB的问题很多,但其中许多问题的答案已经过时,而Mongo 3.x之后并没有考虑这些功能。 我的问题是如何查询带有链接元素条件的表?

这是一个极其简化的示例

const Person =  new mongoose.Schema({
  gender: String
});

const Dog =  new mongoose.Schema({
  breed: String
});

const Team =  new mongoose.Schema({
  trainer: {
        type: mongoose.Schema.ObjectId,
        ref: 'Person'
  },
  members: [{
        type: mongoose.Schema.ObjectId,
        ref: 'Dog'
  }]
})

想象一下这已经在生产中,并且不可能更改架构。

我怎么能找回所有带有至少一只“贵宾犬”犬种的犬 ,并且教练的性别是“雄性”的 队?

用另一种方式提出您的问题:如何在mongoDB中加入两个以上的集合?

假设您的集合名称与模型名称相对是dogsteamspeople (Mongoose复数形式),则以下是获得所需结果的一种方法:

Dog.aggregate([{
        $match: {
            breed: "Poodle"
        }
    },
    {
        $lookup: {
            from: "teams",
            localField: "_id",
            foreignField: "members",
            as: "team"
        }
    },
    {
        $unwind: "$team"
    },
    {
        $lookup: {
            from: "people",
            localField: "team.trainer",
            foreignField: "_id",
            as: "trainer"
        }
    },

    {
        $unwind: "$trainer"
    },

    {
        $match: {
            "trainer.gender": "male"
        }
    },
    {
        $project: {
            breed: 1,
            trainer: 1,
            team: {
                _id: 1
            }
        }
    }
], function(err, teams) {
   console.log(teams)
});

在聚合管道中,我们执行以下操作:

  1. Dog为起点并匹配品种
  2. 然后使用$ lookup将结果加入团队,并获取包含成员引用“ Poodle”的团队
  3. 2中的结果集包含团队数组(您可以删除$ lookup下面的所有步骤以查看结果状态)。 要将数组拆分为另一个文档,我们使用$ unwind运算符(例如,三个元素组成的团队将成为三个文档,并且父字段全部复制)
  4. 在新的结果集上,再次应用$ lookup,这次加入了人们。 这使人们陷入了培训师阵营。
  5. 再次放松以拆分教练
  6. 匹配trainer.gender “ male”的结果集
  7. 您需要的$ project (选择)字段

最终结果将如下所示:

{
    "_id" : ObjectId("596e5500b5174986059958a8"),
    "breed" : "Poodle",
    "team" : {
        "_id" : ObjectId("596e564fb5174986059958de")
    },
    "trainer" : {
        "_id" : ObjectId("596e54bfb51749860599589c"),
        "gender" : "male"
    }
}


{
    "_id" : ObjectId("596e5500b5174986059958a8"),
    "breed" : "Poodle",
    "team" : {
        "_id" : ObjectId("596e564fb5174986059958e6")
    },
    "trainer" : {
        "_id" : ObjectId("596e54bfb51749860599589c"),
        "gender" : "male"
    }
}


{
    "_id" : ObjectId("596e5500b5174986059958b2"),
    "breed" : "Poodle",
    "team" : {
        "_id" : ObjectId("596e564fb5174986059958de")
    },
    "trainer" : {
        "_id" : ObjectId("596e54bfb51749860599589c"),
        "gender" : "male"
    }
}


{
    "_id" : ObjectId("596e5500b5174986059958b2"),
    "breed" : "Poodle",
    "team" : {
        "_id" : ObjectId("596e564fb5174986059958e6")
    },
    "trainer" : {
        "_id" : ObjectId("596e54bfb51749860599589c"),
        "gender" : "male"
    }
}

从本质上讲,我们已经搜索Dog并加入和匹配了更多收藏。 最终文档中的根_id是dog not team的_id,因此从技术上讲,结果集包含包含团队和训练员的dogs,但是您可以将它们视为“团队”文档。 您可以从PersonDog进行另一种方式。

而且,结果的结构也不完美。 您可能想要一种结构良好的格式,因为人口喜欢包含嵌入式trainermembers teams 通过对聚合管道进行一些调整,我确信可以实现结构良好的结构。

最后,这不同于猫鼬的人口,这是另一个答案。 主要区别在于,在这种情况下,您已经将查找所需文档的任务委派给了mongo服务器,并且显然是一次完成的任务。 就人口而言,同样需要太多的客户端处理和对db的许多请求。 但是$ lookup适用于未分片的集合,在这种情况下,您可能更喜欢填充或考虑答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM