掌握MongoDB多表关联查询的技巧

引言

MongoDB是一个非关系型数据库,大受欢迎的原因之一是很方便在多个集合(就是”表”的概念)中进行联合查询。

如果你是初学者,那么你可能会问什么时候需要联合查询。举个例子,如果你有一个学生集合和一个成绩集合,你可能会想要查询一个学生所有课程的成绩。

本文将介绍如何使用MongoDB进行多表联合查询,包括内嵌文档和$lookup操作符两种方法。

内嵌文档

内嵌文档是MongoDB中最基本且最常见的多表联合查询方法。

小标题1:内嵌文档基础

首先,需要知道如何在一个文档中嵌入其他文档。这个操作可以使用Mongo Shell或任何MongoDB操作客户端。这里使用Mongo Shell作为演示。

> db.students.insert({
    "name": "小明",
    "age": 20,
    "score": {
        "math": 80,
        "chinese": 90,
        "english": 85
    }
})

上面这个例子将一个名为”小明”的学生文档插入了学生集合中。此文档有一个嵌套的分数文档。

接下来,我们将展示如何查询学生的成绩记录:

> db.students.find({"name": "小明"})
{ "_id" : ObjectId("60efa25968ca5ef8843f0c0c"), "name" : "小明", "age" : 20, "score" : { "math" : 80, "chinese" : 90, "english" : 85 } }

很简单,只需要将查询条件指定为”name”为”小明”即可。

小标题2:多个文档的联合查询

接下来,我们将学生文档和成绩文档嵌入一个班级文档,以此演示如何使用内嵌文档查询多个文档:

> db.classes.insert({
    "name": "一年级",
    "students": [
        {
            "name": "小明",
            "age": 20,
            "score": {
                "math": 80,
                "chinese": 90,
                "english": 85
            }
        },
        {
            "name": "小红",
            "age": 19,
            "score": {
                "math": 78,
                "chinese": 88,
                "english": 86
            }
        }
    ]
})

上面这个例子将一个名为”一年级”的班级文档插入了班级集合中。此文档有一个嵌套的学生文档数组,数组里包含两个学生文档,每个学生文档有一个嵌套的成绩文档。

接下来,我们将展示如何查询这个班级里所有学生的姓名和成绩记录:

> db.classes.find({}, {"students.name": 1, "students.score": 1})
{ "_id" : ObjectId("60efa5c068ca5ef8843f0c0d"), "students" : [ { "name" : "小明", "score" : { "math" : 80, "chinese" : 90, "english" : 85 } }, { "name" : "小红", "score" : { "math" : 78, "chinese" : 88, "english" : 86 } } ] }

只需将查询条件指定为一个空文档,然后指定需要返回的字段即可。在这个例子中,我们指定了”name”和”score”两个字段。

$lookup操作符

$lookup操作符是MongoDB中用于执行多表联合查询的最强大且最灵活的方法。

小标题1:单个查询

首先,我们需要知道如何使用$lookup操作符查询单个文档中包含的多个子文档。这个操作将会使用到餐厅和菜品两个文档。

> db.restaurants.insert({
    "name": "餐厅1",
    "dishes": [
        {
            "name": "红烧肉",
            "price": 28
        },
        {
            "name": "鱼香肉丝",
            "price": 18
        }
    ]
})

上面这个例子将一个名为”餐厅1″的餐厅文档插入了餐厅集合中。此文档有一个嵌套的菜品文档数组,数组里包含两个菜品文档。

接下来,我们将展示如何查询一个餐厅,并将其菜品信息一并返回:

> db.restaurants.aggregate([
    {
        $match: {"name": "餐厅1"}
    },
    {
        $lookup: {
            from: "dishes",
            localField: "dishes.name",
            foreignField: "name",
            as: "dishes"
        }
    },
    {
        $project: {"dishes.name": 1, "dishes.price": 1}
    }
])

这是一个比较复杂的查询,需要使用聚合管道(aggregate pipeline)来实现。首先使用$match操作符找到名称为”餐厅1″的餐厅文档,并将其作为管道的第一个操作。

然后,使用$lookup操作符查找”dishes”集合,并将其结果嵌入”restaurants”文档中。$lookup操作符需要指定四个参数:

  • from:需要联结的文档集合名
  • localField:连接到当前文档的本地键字段
  • foreignField:连接到目标文档的外键字段
  • as:联结到当前文档的新键名

最后使用$project操作符将$dishes数组中的”name”和”price”字段投影出来。

小标题2:多个查询

现在,我们将举一个更复杂的例子,使用$lookup操作符查询多个文档的联合结果。这个例子将使用到学生、成绩和课程三个文档。

首先,我们需要在Mongo Shell中插入所有的测试文档:

> db.students.insertMany([
    {"name": "小明", "age": 20},
    {"name": "小红", "age": 19}
])
> db.courses.insertMany([
    {"name": "math", "credit": 3},
    {"name": "chinese", "credit": 3},
    {"name": "english", "credit": 2}
])
> db.scores.insertMany([
    {"student": "小明", "course": "math", "score": 80},
    {"student": "小明", "course": "chinese", "score": 90},
    {"student": "小明", "course": "english", "score": 85},
    {"student": "小红", "course": "math", "score": 78},
    {"student": "小红", "course": "chinese", "score": 88},
    {"student": "小红", "course": "english", "score": 86}
])

接下来,我们将展示如何使用$lookup操作符查询所有学生的所有成绩和对应的课程信息:

> db.students.aggregate([
    {
        $lookup: {
            from: "scores",
            localField: "name",
            foreignField: "student",
            as: "scores"
        }
    },
    {
        $unwind: "$scores"
    },
    {
        $lookup: {
            from: "courses",
            localField: "scores.course",
            foreignField: "name",
            as: "course_info"
        }
    },
    {
        $unwind: "$course_info"
    },
    {
        $project: {"name": 1, "course": "$course_info.name", "credit": "$course_info.credit", "score": "$scores.score"}
    }
])

这是一个相对复杂的查询,以便演示如何在多个MongoDB文档中执行联合查询。

首先,使用$lookup操作符将”students”文档和”scores”文档联结起来。将”students.name”字段和”scores.student”字段匹配。联结结果将插入到”students.scores”数组中。

然后,使用$unwind操作符展开”students.scores”数组,以便进行下一步联结。这里使用了两次$unwind,因为后续还会有一个联结操作。

接下来,使用$lookup操作符将课程信息加入联结结果中。将”students.scores.course”字段和”courses.name”字段匹配。联结结果将插入到”students.scores.course_info”数组中。

最后,使用$project操作符来投影出我们想要的结果。在这个例子中,我们将”name”、”course”、”credit”和”score”字段都投影出来。

结论

本文介绍了MongoDB中的两种多表联合查询方法:内嵌文档和$lookup操作符。内嵌文档可以很容易地在一个文档中嵌入其他文档,但是只适用于简单的联合查询场景。$lookup操作符则可以在多个MongoDB文档之间执行更为灵活和复杂的联合查询。这些方法都可以用于多个领域,例如学生成绩、餐厅菜品和体育比赛信息等。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/240369.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 12:21
下一篇 2024-12-12 12:21

相关推荐

  • 使用vscode建立UML图的实践和技巧

    本文将重点介绍在使用vscode在软件开发中如何建立UML图,并且给出操作交互和技巧的指导。 一、概述 在软件开发中,UML图是必不可少的重要工具之一。它为软件架构和各种设计模式的…

    编程 2025-04-29
  • 优秀周记1000字的撰写思路与技巧

    优秀周记是每个编程开发工程师记录自己工作生活的最佳方式之一。本篇文章将从周记的重要性、撰写思路、撰写技巧以及周记的示例代码等角度进行阐述。 一、周记的重要性 作为一名编程开发工程师…

    编程 2025-04-28
  • 堆叠图配色技巧分享

    堆叠图是数据可视化中常用的一种表现形式,而配色则是影响堆叠图观感和传达信息的重要因素之一。本文将分享一些堆叠图配色的技巧,帮助你创造更好的数据可视化。 一、色彩搭配原则 色彩是我们…

    编程 2025-04-27
  • 使用uring_cmd提高开发效率的技巧

    对于编程开发工程师来说,提高效率一直是致力追求的目标。本文将深度解析如何使用uring_cmd,提升工作效率。 一、常用命令 uring_cmd是一个非常强大的命令行工具,但是大部…

    编程 2025-04-27
  • 通信专业Python和Java的开发技巧

    本文旨在介绍通信专业Python和Java的开发技巧,为读者提供实用且可操作的思路和方法。 一、Python在通信领域中的应用 Python是一种优秀的程序设计语言,因其易学易用、…

    编程 2025-04-27
  • 前端引用字体的实现方法和技巧

    对于前端开发人员而言,字体關系着网站的整体美观度和用户体验。为了满足客户,开发人员经常需要引用特定的字体。在这篇文章中,我们将会详细解决前端引用字体的实现方法和技巧。 一、字体引用…

    编程 2025-04-27
  • if not in case – Python中使用if语句进行逻辑判断的技巧

    if语句是Python中进行逻辑判断的基础语句之一。在if语句中,我们可以使用not关键字和in关键字来进行更加灵活的判断。本文将详细介绍Python中使用if not in ca…

    编程 2025-04-27
  • JavaScript中修改style属性的方法和技巧

    一、基本概念和方法 style属性是JavaScript中一个非常重要的属性,它可以用来控制HTML元素的样式,包括颜色、大小、字体等等。这里介绍一些常用的方法: 1、通过Java…

    编程 2025-04-25
  • Python连接MongoDB数据库

    MongoDB是一个流行的开源、非关系型、文档型数据库。Python具有简单、易学的语法、广泛的应用能力,因此它很适合连接MongoDB数据库。本文将从以下几个方面详细讨论Pyth…

    编程 2025-04-25
  • Android文件读取技巧:如何快速获取文件内容

    在Android开发中,读取文件是非常常见的操作。然而,在某些情况下,如果读取文件的操作不够高效,会导致程序出现卡顿、耗时等问题。因此,在本篇文章中,我们将介绍一些Android文…

    编程 2025-04-25

发表回复

登录后才能评论