如何在 MongoDB 中创建查询

作者选择了 开放式互联网/自由言论基金作为 写给捐款计划的一部分,接受捐款。

介绍

存储在 MongoDB 数据库中的文档可能有很大差异;有些文档可能相对较小,并且仅包含少数条条目,例如购物列表中的项目;其他文档可能非常复杂,包含数十个不同类型的字段,包含多个值的数组,甚至包含在更大的结构中嵌入的其他文档。

不管你的文件有多复杂 或有多少 你通常不需要同时审查所有的文件中的数据 相反,你更可能只想要取回符合一个或多个特定条件的文件. 与您如何通过在预订网站上选择一系列过滤器来找到您的假日目的地相似, 例如离海边的距离, 宠物友好, 游泳池, 以及附近的停车场, 您可以精确地询问MongoDB, 以找到您需要的文件 。 蒙戈语Name DB提供了一个强大的查询机制,用于在检索文档时定义过滤标准.

在本教程中,您将学习如何使用不同的过滤器和条件来查询 MongoDB 集合,您还将学习指针是什么以及如何在 MongoDB 壳中使用它们。

前提条件

要遵循本教程,您将需要:

  • 具有`sudo'权限和UFW配置防火墙的普通非根用户的服务器。 使用运行 Ubuntu 20.04 的服务器验证了此教程, 您可以遵循此[ Ubuntu 20. 04 的初始服务器设置教程( https://andsky.com/tech/tutorials/initial-server-setup-with-ubuntu-20-04) 来准备您的服务器 。
  • 蒙戈语 DB 安装在您的服务器上 。 要设置此功能,请遵循我们关于[如何在Ubuntu 20.04上安装MongoDB]的教程(https://andsky.com/tech/tutorials/how-to-install-mongodb-on-ubuntu-20-04)。
  • 联合国 您服务器的 MongoDB 实例通过允许认证和创建行政用户而获得安全 。 为了保证蒙戈DB的安全,请遵守我们关于)。
  • 熟悉MongoDB CRUD操作,特别是从收藏中检索对象。 要学习如何使用MongoDB shell来进行 CRUD 操作,请遵循教程 [如何在 MongoDB 中执行 CRUD 操作 (https://andsky.com/tech/tutorials/how-to-perform-crud-operations-in-mongodb). .

<$>[注] 注: 有关如何配置您的服务器,安装,然后安全MongoDB安装的链接教程是指Ubuntu 20.04.本教程专注于MongoDB本身,而不是潜在的操作系统。

步骤 1 - 准备样本数据库

要解释如何在 MongoDB 中创建查询 — 包括如何过滤多个字段、嵌入式文档和数组的文档 — 此指南使用包含描述世界五座最高山的文档集合的示例数据库。

要创建此样本集合,请连接到 MongoDB 壳作为您的管理用户。本教程遵循前提条件的惯例 MongoDB 安全教程并假定这个管理用户的名字是 AdminSammy 及其身份验证数据库是 admin. 请确保在下面的命令中更改这些细节以反映您自己的设置,如果不同:

1mongo -u AdminSammy -p --authenticationDatabase admin

当被提示时,请输入您创建管理用户时设置的密码. 提供密码后,您的提示将更改为大于(>)的符号:

注意:在新连接时,MongoDB 壳将自动连接到测试数据库,默认情况下,您可以安全地使用此数据库来实验 MongoDB 和 MongoDB 壳。

或者,您也可以切换到另一个数据库以运行本教程中提供的所有示例命令. 要切换到另一个数据库,请运行使用命令,然后是您的数据库名称:

1use database_name

美元

要了解 MongoDB 如何过滤多个字段、嵌入式文档和数组的文档,您需要足够复杂的样本数据来探索不同类型的查询。

本集合中的文档将遵循此格式.本示例文档描述了埃弗雷斯山:

 1[label Mount Everest document]
 2{
 3    "name": "Everest",
 4    "height": 8848,
 5    "location": ["Nepal", "China"],
 6    "ascents": {
 7        "first": {
 8            "year": 1953,
 9        },
10        "first_winter": {
11            "year": 1980,
12        },
13        "total": 5656,
14    }
15}

本文档包含以下字段和值:

  • `名称':峰名
  • :峰高,以米计
  • " 地点 " :山地所在国。 此字段存储值为数组, 以允许位于不止一个国家的山脉
  • `上升':这个字段的价值是另一个文件。 当一个文档存储在这样的另一个文档中时,它被称为_嵌入_或_nested_文档. 每一份 " 升起 " 文件都描述了该山的成功升起。 具体地说,每份 " 升起 " 文件都包含一个 " 总 " 字段,列出每个高峰的成功升起总数。 此外,每个嵌入式文件都包含两个字段,其值也是嵌入式文件:
  • 第一':这个领域的价值是一份包含一个领域年份'的嵌入式文件,其中说明第一个整体成功上升的年份
  • 第一个冬季':这个字段的价值是一个嵌入式文件,其中也包含一个年'字段,其价值是给定山的第一个冬季成功升起的年份

为什么第一个升降被代表为嵌套文件,即使现在只包含了年份,是因为它可以更容易地扩展升降细节,以更多的领域在未来,如山峰的名字或探险的细节。

在 MongoDB 壳中运行以下insertMany()方法,同时创建一个名为peaks的集合,并将五个样本文档插入其中。

 1db.peaks.insertMany([
 2    {
 3        "name": "Everest",
 4        "height": 8848,
 5        "location": ["Nepal", "China"],
 6        "ascents": {
 7            "first": {
 8                "year": 1953
 9            },
10            "first_winter": {
11                "year": 1980
12            },
13            "total": 5656
14        }
15    },
16    {
17        "name": "K2",
18        "height": 8611,
19        "location": ["Pakistan", "China"],
20        "ascents": {
21            "first": {
22                "year": 1954
23            },
24            "first_winter": {
25                "year": 1921
26            },
27            "total": 306
28        }
29    },
30    {
31        "name": "Kangchenjunga",
32        "height": 8586,
33        "location": ["Nepal", "India"],
34        "ascents": {
35            "first": {
36                "year": 1955
37            },
38            "first_winter": {
39                "year": 1986
40            },
41            "total": 283
42        }
43    },
44    {
45        "name": "Lhotse",
46        "height": 8516,
47        "location": ["Nepal", "China"],
48        "ascents": {
49            "first": {
50                "year": 1956
51            },
52            "first_winter": {
53                "year": 1988
54            },
55            "total": 461
56        }
57    },
58    {
59        "name": "Makalu",
60        "height": 8485,
61        "location": ["China", "Nepal"],
62        "ascents": {
63            "first": {
64                "year": 1955
65            },
66            "first_winter": {
67                "year": 2009
68            },
69            "total": 361
70        }
71    }
72])

输出将包含新插入对象分配的对象标识符列表。

 1[secondary_label Output]
 2{
 3        "acknowledged" : true,
 4        "insertedIds" : [
 5                ObjectId("610c23828a94efbbf0cf6004"),
 6                ObjectId("610c23828a94efbbf0cf6005"),
 7                ObjectId("610c23828a94efbbf0cf6006"),
 8                ObjectId("610c23828a94efbbf0cf6007"),
 9                ObjectId("610c23828a94efbbf0cf6008")
10        ]
11}

您可以通过运行无参数的 find() 方法来验证文档是否正确插入,这将检索您刚刚添加的所有文档:

1db.peaks.find()
1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3
4. . .

通过此,您已经成功创建了山的示例文档列表,这些文档将作为创建查询的测试数据。

步骤 2 - 寻找个别字段

在之前的步骤结束时,您使用了MongoDB的find()方法来返回来自peaks集合的每个文档,但是这样的查询在实践中并不非常有用,因为它不会过滤任何文档,并且总是返回相同的结果集。

您可以通过定义文档必须遵守的特定条件来过滤MongoDB中的查询结果. 如果您已经遵循了(https://andsky.com/tech/tutorials/how-to-perform-crud-operations-in-mongodb)教程,您已经使用了最基本的过滤条件:平等条件。

例如,运行以下查询,返回任何具有名称值等于Everest的文档:

1db.peaks.find(
2    { "name": "Everest" }
3)

第二行──「名稱:Everest」───是問卷文件──一個指定要在搜尋集合時應用過濾器的JSON對象,以便找到符合該條件的文件.此示例操作告訴MongoDB在「峰值」集合中搜尋任何「名稱」值匹配「Everest」字串的文件:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }

MongoDB返回了一份单一的文件,因为在收藏中只有一座珠峰。

平等条件指定一个单个值,MongoDB 将尝试与集合中的文档匹配。MongoDB 提供 _comparison 查询运算符,允许您指定其他条件,这些条件也指向单个字段,但过滤文档的方式比搜索准确匹配更为复杂。

比较运算器由运算器本身组成,一个单一的密钥由美元符号(‘$’)先行,以及查询运算器将使用的值来过滤文档。

为了说明,运行以下查询,搜索任何名称值不等于Everest的文档:

1db.peaks.find(
2    { "name": { $ne: "Everest" } }
3)

此时,查询过滤文件包含 { $ne: "Everest" }. $ne' 是本示例中的比较运算符,它代表不等式。 峰值名称 Everest’ 再次出现在该运算符的值中。

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586, "location" : [ "Nepal", "India" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 1986 }, "total" : 283 } }
4. . .

$in操作符允许您编写查询,这些查询将返回具有数组中包含的多个值之一的值的文档。

下面的示例查询包括$in运算符,并将返回与EverestK2相匹配的名称值的文档:

1db.peaks.find(
2    { "name": { $in: ["Everest", "K2"] } }
3)

代替单个值,传递给$in运算符的值是两个圆形块中的顶级名称组合,MongoDB 返回两个文件,就像预期的那样:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }

此前的示例已查询了用文本值的名称字段,您还可以根据数字值过滤文档。

以下示例查询搜索高度值大于8500的文档:

1db.peaks.find(
2    { "height": { $gt: 8500 } }
3)

此查询包括$gt运算符,它代表大于_。通过传输值8500,MongoDB 将返回文件的高度值大于8500:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }
4{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586, "location" : [ "Nepal", "India" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 1986 }, "total" : 283 } }
5{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }

MongoDB 除了本节中列出的操作员外,还提供了一些比较查询操作员。 有关这些操作员的完整列表,请参阅 有关该主题的官方文档

现在您已经知道如何在单个文档字段中使用平等条件和比较运算符,您可以继续学习如何将多个条件合并到一个查询中。

第3步:使用多个条件

有时基于单个文档字段的过滤不足以准确选择感兴趣的文档,在这种情况下,您可能希望使用多个条件同时过滤文档。

在 MongoDB 中连接多个条件有两种方法,第一种是使用逻辑 AND 连接来选择符合 all 条件的集合中的文档,或者使用逻辑 OR 从列表中选择符合 至少一个 条件的文档。

在 MongoDB 中,在查询过滤文件中使用多个字段时, AND 连接是默认的. 尝试选择匹配 Everest 名称和 8848 米的高度的山:

1db.peaks.find(
2    { "name": "Everest", "height": 8848 }
3)

请注意,语法类似于前一个步骤中的平等条件示例,但这次在查询过滤文件中出现两个字段。

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }

在这种情况下,返回一个单一的文档,但如果您尝试将高度更改为任何其他数字值,结果将是空的,因为任何返回的文档都必须符合这两个条件。

1db.peaks.find(
2    { "name": "Everest", "height": 9000 }
3)

此默认 AND 可以通过包括$and逻辑查询运算符,然后列出返回文档必须满足的条件。

1db.peaks.find(
2    { $and: [{"name": "Everest"}, {"height": 8848}] }
3)

这次包含$and查询运算符的 JSON 对象是查询过滤文件本身,在这里,比较运算符在列表中出现的两个单独的平等条件,一个用于名称匹配,另一个用于高度匹配。

若要选择符合任何选择条件的文档,而不是全部,则可以使用$or操作符:

1db.peaks.find(
2    { $or: [{"name": "Everest"}, {"name": "K2"}] }
3)

当使用$or运算符时,文档只需要满足两个等式过滤器中的一个:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }

虽然本示例中的每个条件都是单场平等条件,但$and$or运算符可以包含任何有效的查询过滤文件,甚至可以包含嵌入式 AND/OR 条件列表。

如本步骤所述,使用$and$or运算符连接多个过滤器可以非常有助于检索精细的查询结果,但是,到目前为止,所有示例都使用了基于单个值的查询过滤文件。

步骤 4 — 查找 Array 值

有时一个单个字段可能包含数组中存储的多个值。在我们的山峰示例中,位置就是这样一个字段. 因为山区通常覆盖一个以上的国家,例如尼泊尔和印度的Kangchenjunga,一个单一值可能并不总是足够的这个字段。

在此步骤中,您将学习如何构建匹配数组字段中的项目的查询过滤器。

首先,让我们尝试选择代表尼泊尔山脉的文件,但对于这个例子来说,如果山脉列出了多个地点,只要其中一个是尼泊尔就没问题了:

1db.peaks.find(
2    { "location": "Nepal" }
3)

此查询使用一个平等条件,告诉 MongoDB 返回文档,其位置值完全匹配给定的字符串值尼泊尔,类似于以前使用名称字段的示例。

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586, "location" : [ "Nepal", "India" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 1986 }, "total" : 283 } }
4{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }
5{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }

对于这个查询,MongoDB返回了四个文件,其中尼泊尔出现在位置字段中。

但是,如果你想找到位于中国和尼泊尔的山脉,怎么办? 要做到这一点,你可以在过滤文件中包含一个数组,而不是一个单一的值:

1db.peaks.find(
2    { "location": ["China", "Nepal"] }
3)

虽然数据库中有 4 个 尼泊尔 和 中国 山脉,但只有 1 个 列出了该 国家在本查询中给出的顺序,因此此查询返回一个单一的文档:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }

请注意,对 Makalu 的位置字段的值与查询的过滤文件相同。当您提供一个数组作为对等条件的值时,MongoDB 会检索文件,其中位置字段准确匹配查询过滤器,包括数组内部元素的顺序。

1db.peaks.find(
2    { "location": ["Nepal", "China"] }
3)
1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }

现在,又有两座山返回了,但马卡卢没有。

使用这样的平等条件在你只关心数组中的元素(不论它们的顺序)的情况下并不有帮助,而不是准确匹配。

为了说明,运行以下查询:

1db.peaks.find(
2    { "location": { $all: ["China", "Nepal"] } }
3)

$all操作员将确保文件被检查是否包含中国和尼泊尔在任何顺序中。

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }
4{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }

本步骤描述了如何在查询过滤文件中使用数组来检索单个字段中具有多个值的文档. 如果您想要查询嵌入文档中的数据,则需要使用此操作所需的特殊语法。

步骤5 — 在嵌入式文档中查询字段

请记住,示例数据库文档中包含一个上升字段,该字段包含有关每个山的第一个上升的各种细节,以此方式,在构建查询时,有关第一个上升、冬季上升和上升总数的数据将清晰地组合到单个嵌入文档中。

再次审查样本珠峰文件:

 1[label The Everest document]
 2{
 3    "name": "Everest",
 4    "height": 8848,
 5    "location": ["Nepal", "China"],
 6    "ascents": {
 7        "first": {
 8            "year": 1953,
 9        },
10        "first_winter": {
11            "year": 1980,
12        },
13        "total": 5656,
14    }
15}

访问名称高度字段很简单,因为这些键下方有一个单一值,但假设您想要找到特定峰值的上升总数。

为了解决这个问题,MongoDB 提供了 _dot 符号,用于访问嵌入式文档中的字段。

要说明 MongoDB 的点符号是如何工作的,请运行下面的查询. 这将返回集合中已升高超过 1000 次的所有山脉,使用前面突出的 $gt 操作员:

1db.peaks.find(
2    { "ascents.total": { $gt: 1000 } }
3)

珠穆朗玛峰是收藏中唯一一座有1000多次登山的山峰,因此只会返回其文件:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }

虽然使用$gt运算器的{ $gt: 1000 }查询过滤器很熟悉,但请注意该查询如何访问存储在ascents字段中的文档中的字段。

因此,ascents.total意味着MongoDB首先应该打开ascents字段指向的嵌入文档,然后在其中找到total字段。

标注也适用于多个嵌入式文件:

1db.peaks.find(
2    { "ascents.first_winter.year": { $gt: 2000 } }
3)

此查询将返回描述在2000年之后首次在冬季登山的山脉的文件:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }

如前所述,ascents.first_winter.year标记意味着MongoDB首先找到ascents字段并在那里找到嵌入的文档,然后进入另一个嵌入的文档,即first_winter,并最终从其内部获取year字段。

点符号可用于访问 MongoDB 中的任何深度嵌入文档。

到目前为止,您将了解如何访问嵌入式文档中的数据以及如何过滤查询结果,您可以继续学习如何限制查询返回的域列表。

步骤 6 — 返回字段子集

在迄今为止的所有示例中,每当您查询峰值集合时,MongoDB 都会返回一个或多个完整的文档。

这不仅仅是可读性问题,也是性能问题,如果只需要一个文档的一小部分,那么在数据库上检索整个文档对象将是一个不必要的性能负担。

例如,假设您只对存储在峰值集合中的山脉名称感兴趣,但这一次上升的细节或位置并不重要。

投影文档是一个 JSON 对象,其中密钥对应到被查询的文档中的字段。 投影可以构建为 inclusion projectionsexclusion projections. 当投影文档中包含具有 `1 值的字段时,它描述了将被包含在结果中的字段列表。

运行以下查询,其中包括已知的)方法包含两个参数,而不是一个。第一个,{},是查询过滤文件。这里是一个空的JSON对象,这意味着它不会应用任何过滤。第二个参数,{名称:1 },描述了投影,意味着查询结果只包含每个文件的名称`字段:

1db.peaks.find(
2    {},
3    { "name": 1 }
4)

运行此示例查询后,MongoDB 会返回以下结果:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest" }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2" }
4{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga" }
5{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse" }
6{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu" }

请注意,返回的文档简化,只包含名称_id字段。

要说明如何指定要排除哪些字段,请运行以下查询. 它将返回来自每个文档的数据,但将排除上升位置字段:

1db.peaks.find(
2    {},
3    { "ascents": 0, "location": 0 }
4)

MongoDB 再次返回所有五个山,但这一次只有名称高度_id字段:

1[secondary_label Output]
2{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848 }
3{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611 }
4{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586 }
5{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516 }
6{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485 }

<$>[注] 注: 指定预测时,您不能混合包括和排除,您必须指定要包含的字段列表或要排除的字段列表。

但是,此规则有一个例外。 MongoDB 允许您将 _id 字段从结果集中排除,即使在查询中应用了包含投影时。 若要删除 _id 字段,您可以将 `"_id": 0' 附加到投影文档中。

1db.peaks.find(
2    {},
3    { "_id": 0, "name": 1 }
4)
1[secondary_label Output]
2{ "name" : "Everest" }
3{ "name" : "K2" }
4{ "name" : "Kangchenjunga" }
5{ "name" : "Lhotse" }
6{ "name" : "Makalu" }

美元

投影也可以用来包括或排除嵌入文档中的字段,例如,你想知道每个山的第一个冬季升降和总升降数,这两个字段都嵌入到升降字段中。

1db.peaks.find(
2    {},
3    { "_id": 0, "name": 1, "ascents": { "first_winter": 1, "total": 1 } }
4)

请注意,投影是如何为升起字段指定的,以及它是如何遵循嵌套文档的结构,而它本身就是嵌套投影。 使用first_winter:1,total:1`这个查询告诉数据库仅包括嵌套文档中的这两个字段,而不是其他。

返回的文件只包含所要求的字段:

1[secondary_label Output]
2{ "name" : "Everest", "ascents" : { "first_winter" : { "year" : 1980 }, "total" : 5656 } }
3{ "name" : "K2", "ascents" : { "first_winter" : { "year" : 1921 }, "total" : 306 } }
4{ "name" : "Kangchenjunga", "ascents" : { "first_winter" : { "year" : 1988 }, "total" : 461 } }
5{ "name" : "Makalu", "ascents" : { "first_winter" : { "year" : 2009 }, "total" : 361 } }

将返回文档的大小限制在一个子集的字段中,可以有助于使结果集更易于读取,甚至可以提高性能。

步骤 7 — 使用指标来排序和限制查询结果

在从大集合中获取对象时,可能有时你想要限制结果的数量,或者可能把它们排序成一个特定的顺序,例如,购物网站的常见方法是按价格排序产品,MongoDB 使用 cursors 允许你限制查询结果集中返回的文档数量,并以上升或下降顺序排序结果。

请记住从步骤 1 中的此示例查询:

1db.peaks.find()

您可能还记得,此查询返回的结果集包括在峰值集合中的每个文档中的所有数据。 虽然它看起来像MongoDB返回了峰值集合中的所有对象,但情况并非如此。

指示器是指向查询的结果集的指示器,但不是结果设置本身。 它是一个可以迭代的对象,这意味着您可以要求指示器在行中返回 _next 文档,然后将从数据库中获取完整的文档。

借助方程式,MongoDB 可以确保实际的文档检索只有在需要时才会发生。

要说明标记器是如何工作的,请执行以下操作,其中包括)`方法:

1db.peaks.find().count()

MongoDB 會以「5」回應:

1[secondary_label Output]
25

在罩下, " find() " 方法查找并返回光标,然后将 " counts() " 方法调用在该光标上。 这让蒙戈 DB知道你对对象计数感兴趣,而不是文档本身. 这意味着文档不会成为结果的一部分——所有数据库会返回是计数. 在从光标取回文档之前,使用光标上的方法对查询进行进一步修改,您可以确保只执行您要求的数据库操作.

注意:在执行查询时,MongoDB shell 会自动重复返回的标记器 20 次,以便在屏幕上显示前 20 个结果。

另一种 MongoDB 方法使用标记器来更改结果集是)`来限制查询将返回的结果的数量。

运行以下查询,仅从收藏中获取三座山峰:

1db.peaks.find(
2    {},
3    { "_id": 0, "name": 1, "height": 1 }
4).limit(3)

MongoDB 壳将用三个对象来响应,而不是五个,即使查询没有过滤任何数据:

1[secondary_label Output]
2{ "name" : "Everest", "height" : 8848 }
3{ "name" : "K2", "height" : 8611 }
4{ "name" : "Kangchenjunga", "height" : 8586 }

应用于路由器的)`路由器方法在大型集合中将有助于确保您只获得所需的结果,而不是更多。

默认情况下,MongoDB 会按其插入的顺序返回对象,但您可能希望更改这种行为。 假设您有兴趣在数据库中找到三个最低的山峰。

1db.peaks.find(
2    {},
3    { "_id": 0, "name": 1, "height": 1 }
4).limit(3).sort({ "height": 1 })

添加的 sort({ "height": 1 }) 会使结果设置与上一个示例不同:

1[secondary_label Output]
2{ "name" : "Makalu", "height" : 8485 }
3{ "name" : "Lhotse", "height" : 8516 }
4{ "name" : "Kangchenjunga", "height" : 8586 }

再次,只有三座山峰被返回,但是,这一次,它们已经从具有最低高度值的山峰上来排序。

路由器上的 sort() 方法接受一个 JSON 对象 - height - 作为一个参数,类似于投影文档. 它也接受将用于对应排序的键列表。

结论

通过阅读本文,您了解了 MongoDB 如何使用它来过滤查询结果,您对单个字段、多个条件和复杂结构进行过滤,例如数组和嵌入式文档。

该教程只描述了一小部分由MongoDB提交的查询操作员,以便准确的文档查询。您可以研究官方的MongoDB文档(https://docs.mongodb.com/v4.4/mongo/)了解更多关于不同的查询操作员。

Published At
Categories with 技术
Tagged with
comments powered by Disqus