如果您刚开始接触 MongoDB,很可能已经遇到文档结构变得有些复杂的情况。数据可能从扁平、接近关系型的样子,逐步演变为包含嵌套对象、嵌套数组,甚至四五层嵌套的结构。那么,当数据嵌套了好几层时,如何进行查询呢?
在这篇简短教程中,我们将了解 MongoDB 中的点号表示法,看看如何基于嵌套字段中包含特定值的数据,快速而简单地筛选文档。
所谓点号表示法,指的是用句点字符作为分隔符来分隔嵌套字段。例如:
root_field.nested_field_1.next_layer_nested_field_1技术支持
对于每一层嵌套,我们在查询时只需用一个句点字符将这一层分隔开。随着教程的推进,我们会看到更完整的示例。
如果您刚开始使用 MongoDB,务必查看 DataCamp 的Python 中的 MongoDB 入门课程。
先决条件
要顺利完成本教程,您需要已部署并配置好一个 MongoDB 实例。这意味着您已经准备好开始使用 MongoDB。同时,您至少应对在 MongoDB 中查询集合有基本了解。如果需要帮助,可以从文档开始。
在本示例中,我们将在名为 "dbinc" 的数据库和 "people" 集合中使用以下数据:
[
{
"name": "Nic Raboy",
"websites": [
{
"type": "other",
"name": "Portfolio",
"url": "https://www.nraboy.com"
},
{
"type": "social",
"name": "LinkedIn",
"url": "https://www.linkedin.com/in/nraboy"
}
],
"employment": {
"employer": "MongoDB",
"address": {
"street": "1633 Broadway",
"city": "New York",
"state": "New York",
"postal_code": 10019
}
}
},
{
"name": "Tony Kim",
"websites": [
{
"type": "social",
"name": "LinkedIn",
"url": "https://www.linkedin.com/in/hyung-kim/"
},
{
"type": "coding",
"name": "GitHub",
"url": "https://github.com/hjkmines"
}
],
"employment": {
"employer": "MongoDB",
"address": {
"street": "1633 Broadway",
"city": "New York",
"state": "New York",
"postal_code": 10019
}
}
}
]技术支持
上述数据包含两个文档,由于存在嵌套对象和数组,复杂度不低。顺带一提,MongoDB 在 BSON 文档中支持超过 100 层的嵌套。
如果您计划跟着操作,请确保这些文档已存在于您的 MongoDB 实例中。
在 MongoDB 中用多种方式查询数据
我们将从简单开始,逐步过渡到更复杂的情况。好消息是,这里的“复杂”并不意味着“困难”。
假设我们想查找集合中所有在 MongoDB 工作的人。我们可以执行如下查询:
use dbinc;
db.people.find({
"employment.employer": "MongoDB"
});技术支持
在此示例中,employer 是 employment 对象内的嵌套字段。我们可以使用点号表示法来查询该字段,也就是用句点分隔字段。这与查找所有在纽约工作的人员没有区别。我们可以这样做:
use dbinc;
db.people.find({
"employment.address.state": "New York"
});技术支持
上述查询深入到文档的第三级,但依然可以正常工作。
现在,让我们看看如何处理那个嵌套的对象数组。根据目标不同,有几种查询方式。
假设我们想返回所有列出“Portfolio”网站的人。可以执行如下查询:
use dbinc;
db.people.find({
"websites.name": "Portfolio"
});技术支持
上述查询将返回一条结果,因为只有一个文档列出了“Portfolio”。请注意,即使这是一个数组,点号表示法依然适用。需要注意的是,“Portfolio”必须至少在该数组的某处出现一次。
接下来会更有意思。
假设我们想进一步收紧返回结果。通常我们会增加更多过滤条件,但在处理数组中的嵌套对象时,情况会有些不同。以以下为例:
use dbinc;
db.people.find({
"websites.name": "Portfolio",
"websites.type": "social"
});技术支持
上面的示例表示我们需要“Portfolio”和“social”同时存在于数组中,但不一定在同一个对象里。我们只得到一个结果,因为“Tony Kim”文档包含“social”,但没有“Portfolio”。如果我们需要两个字段必须出现在同一个对象中,就不能只用点号表示法。
虽然超出本教程范围,但可以使用 $elemMatch 运算符来实现:
use dbinc;
db.people.find(
{
"websites": {
"$elemMatch": {
"name": "Portfolio",
"type": "social"
}
}
}
);技术支持
由于示例数据中没有在同一个对象里同时包含匹配的 name 和 type,因此上述查询不会返回任何结果。
如果您在处理数组并且知道要使用的数组索引,仍然可以继续使用点号表示法。例如:
use dbinc;
db.people.find({
"websites.0.name": "Portfolio"
});技术支持
上述查询使用了要匹配的数组索引。在这个场景中,我们希望返回所有文档,这些文档中数组的第一个元素的 name 为“Portfolio”。
虽然超出本教程范围,但需要指出,点号表示法并不限于只读查询。您可以在更新操作、投影以及聚合管道中像这里一样使用点号表示法。
结语
您刚刚快速了解了在 MongoDB 查询中使用点号表示法。我们学习了:
- 点号表示法适用于嵌套对象。
- 数组也可以使用点号表示法,但具体效果会受您对数组期望的限制影响。
$elemMatch 运算符用于在单个数组对象内同时匹配多个字段。
- 如需查询数组中的特定元素,可以在点号表示法中使用数组索引。
MongoDB 集合中的数据很可能不是扁平的,这意味着在某个阶段,您很可能会遇到嵌套对象、嵌套数组、对象中的嵌套数组,或其他各种复杂组合。好消息是,MongoDB 借助其强大的查询 API,使处理这些信息变得轻而易举。
如果您尚未使用 MongoDB,可以了解MongoDB Atlas,或查看我关于通过 Docker 快速上手 MongoDB的另一篇教程。您还可以在我们的独立指南中了解MongoDB 认证。
如果您刚开始接触 MongoDB,很可能已经遇到文档结构变得有些复杂的情况。数据可能从扁平、接近关系型的样子,逐步演变为包含嵌套对象、嵌套数组,甚至四五层嵌套的结构。那么,当数据嵌套了好几层时,如何进行查询呢?
在这篇简短教程中,我们将了解 MongoDB 中的点号表示法,看看如何基于嵌套字段中包含特定值的数据,快速而简单地筛选文档。
所谓点号表示法,指的是用句点字符作为分隔符来分隔嵌套字段。例如:
对于每一层嵌套,我们在查询时只需用一个句点字符将这一层分隔开。随着教程的推进,我们会看到更完整的示例。
如果您刚开始使用 MongoDB,务必查看 DataCamp 的Python 中的 MongoDB 入门课程。
先决条件
要顺利完成本教程,您需要已部署并配置好一个 MongoDB 实例。这意味着您已经准备好开始使用 MongoDB。同时,您至少应对在 MongoDB 中查询集合有基本了解。如果需要帮助,可以从文档开始。
在本示例中,我们将在名为 "dbinc" 的数据库和 "people" 集合中使用以下数据:
上述数据包含两个文档,由于存在嵌套对象和数组,复杂度不低。顺带一提,MongoDB 在 BSON 文档中支持超过 100 层的嵌套。
如果您计划跟着操作,请确保这些文档已存在于您的 MongoDB 实例中。
在 MongoDB 中用多种方式查询数据
我们将从简单开始,逐步过渡到更复杂的情况。好消息是,这里的“复杂”并不意味着“困难”。
假设我们想查找集合中所有在 MongoDB 工作的人。我们可以执行如下查询:
在此示例中,
employer是employment对象内的嵌套字段。我们可以使用点号表示法来查询该字段,也就是用句点分隔字段。这与查找所有在纽约工作的人员没有区别。我们可以这样做:上述查询深入到文档的第三级,但依然可以正常工作。
现在,让我们看看如何处理那个嵌套的对象数组。根据目标不同,有几种查询方式。
假设我们想返回所有列出“Portfolio”网站的人。可以执行如下查询:
上述查询将返回一条结果,因为只有一个文档列出了“Portfolio”。请注意,即使这是一个数组,点号表示法依然适用。需要注意的是,“Portfolio”必须至少在该数组的某处出现一次。
接下来会更有意思。
假设我们想进一步收紧返回结果。通常我们会增加更多过滤条件,但在处理数组中的嵌套对象时,情况会有些不同。以以下为例:
上面的示例表示我们需要“Portfolio”和“social”同时存在于数组中,但不一定在同一个对象里。我们只得到一个结果,因为“Tony Kim”文档包含“social”,但没有“Portfolio”。如果我们需要两个字段必须出现在同一个对象中,就不能只用点号表示法。
虽然超出本教程范围,但可以使用
$elemMatch运算符来实现:由于示例数据中没有在同一个对象里同时包含匹配的
name和type,因此上述查询不会返回任何结果。如果您在处理数组并且知道要使用的数组索引,仍然可以继续使用点号表示法。例如:
上述查询使用了要匹配的数组索引。在这个场景中,我们希望返回所有文档,这些文档中数组的第一个元素的
name为“Portfolio”。虽然超出本教程范围,但需要指出,点号表示法并不限于只读查询。您可以在更新操作、投影以及聚合管道中像这里一样使用点号表示法。
结语
您刚刚快速了解了在 MongoDB 查询中使用点号表示法。我们学习了:
$elemMatch运算符用于在单个数组对象内同时匹配多个字段。MongoDB 集合中的数据很可能不是扁平的,这意味着在某个阶段,您很可能会遇到嵌套对象、嵌套数组、对象中的嵌套数组,或其他各种复杂组合。好消息是,MongoDB 借助其强大的查询 API,使处理这些信息变得轻而易举。
如果您尚未使用 MongoDB,可以了解MongoDB Atlas,或查看我关于通过 Docker 快速上手 MongoDB的另一篇教程。您还可以在我们的独立指南中了解MongoDB 认证。