在使用 NoSQL 数据库 MongoDB 进行数据存储时,常常会涉及到跨文档的查询操作。为了方便地进行跨文档查询,我们可以使用 Mongoose 软件包提供的关联查询功能。在本文中,我们将深入探讨 MongoDB 和 Mongoose 的关联查询原理,并提供实际的示例代码。
MongoDB 关联查询
在 MongoDB 中,数据存储为多个文档的集合。如果一个文档需要引用另一个文档中的数据,我们可以使用 MongoDB 的内嵌文档或引用文档的方式。内嵌文档将一个文档嵌套在另一个文档中,而引用文档则通过一个唯一标识符来引用其他的文档。
内嵌文档
内嵌文档是将一个文档嵌套在另一个文档中。在内嵌文档中,我们可以使用 MongoDB 的 dot notation(点符号)来访问嵌套文档中的字段。下面是一个嵌套文档的示例:
-- -------------------- ---- ------- - ---- ------------------------------------- ----- ------- ---- --- -------- - ------- ---- ---- ---- ----- ---- ------ ------ ----- ---- ------- - -
在上面的示例中,我们创建了一个名为 "John" 的人物文档,并在其内部嵌套了一个地址文档。我们可以使用下面的代码来访问该地址文档中的字段:
// 获取文档中的地址 db.people.findOne()._doc.address // 访问文档中的某个地址字段 db.people.findOne()._doc.address.city
引用文档
引用文档是通过一个唯一标识符来引用其他的文档。在引用文档中,我们需要将文档的 _id 字段作为引用字段,然后再通过 populate() 方法来实现关联查询。下面是一个引用文档的示例:
-- -------------------- ---- ------- -- ---- -- - ---- ------------------------------------- ----- ------ - -- ---- -- - ---- ------------------------------------- ------ --- ----- ------ -------- ------ -------- ------- ------------------------------------ -
在上面的示例中,我们创建了一个名为 "John" 的 User 文档和一个 title 为 "My First Post" 的 Post 文档。注意到在 Post 文档中,我们使用了 User 文档的 _id 字段来引用该文章的作者。现在我们可以使用以下代码来获取该文章的作者:
// 关联查询获取作者 Post.findOne({ _id: "5f5a636ae5e5cb4471ec01d8" }) .populate("author") .exec(function (err, post) { console.log(post.author); });
在上面的代码中,我们使用 Post.findOne() 方法来查询文章,然后使用 populate() 方法来关联查询该文章的作者。populate() 方法接受一个字符串参数,该参数指定要关联查询的字段名称,然后返回一个查询结果,该结果包含了该字段的完整文档。最后使用 exec() 方法来执行查询。
Mongoose 关联查询
在使用 Mongoose 进行 MongoDB 数据库操作时,我们可以使用 Schema 和 Model 来定义文档的结构和操作。Mongoose 提供了一些方法来方便地进行关联查询:
ref
:用于指定引用文档的 Model。populate()
:用于实现关联查询,并返回一个查询结果。aggregate()
:用于实现聚合查询,并返回一个聚合结果。
ref 属性
在 Mongoose 中,我们可以使用 ref
属性来指定引用文档的 Model。下面是一个定义了两个 Model 的示例:
-- -------------------- ---- ------- -- -- ---- - ---- ----- ----- ---------- - --- ----------------- --------- ------- --------- ------ --- ----- ---------- - --- ----------------- ------ ------- -------- ------- ------- - ----- ------------------------------- ---- ------ - --- ----- ---- - ---------------------- ------------ ----- ---- - ---------------------- ------------
在上面的示例中,我们使用了 ref
属性来指定了 Post 文档中引用了 User 文档。这样定义之后,我们可以使用 populate() 方法来实现关联查询。
populate() 方法
使用 populate() 方法可以方便地进行关联查询。下面是一个关联查询的示例:
Post.findOne({ _id: "5f5a636ae5e5cb4471ec01d8" }) .populate("author") .exec(function (err, post) { console.log(post.author); });
在上面的示例中,我们使用了 Post.findOne() 方法来查询一篇文章,然后使用 populate() 方法来关联查询该文章的作者。注意到在 populate() 方法中,我们使用了 "author" 字符串来指定要关联查询的字段名称。这个名称应该与 ref
属性指定的 Model 名称一致。
aggregate() 方法
在 Mongoose 中,我们可以使用 aggregate()
方法来进行聚合查询。下面是一个使用 aggregate()
方法的示例:
-- -------------------- ---- ------- ---------------- - -------- - ----- -------- ----------- --------- ------------- ------ --- -------- - - ---------------- ----- -------- - --------------------- ---
在上面的示例中,我们使用了 aggregate()
方法来查询文章并做聚合操作。聚合操作中,我们使用了 $lookup
操作符来查找 User 文档。$lookup
操作符接受一个对象参数,该参数包含要关联查询的 Collection 名称(from)、当前 Model 的连接字段(localField)、关联 Model 的连接字段(foreignField)和查询结果的字段名称(as)。最后我们使用 exec() 方法来执行查询,并输出查询结果。
总结
通过本文的深入讨论,我们了解了 MongoDB 的内嵌文档和引用文档的两种关联方式,以及 Mongoose 的 ref 属性、populate() 方法和 aggregate() 方法。我们可以根据具体业务需求选择合适的关联方式,以便更好地实现 MongoDB 的跨文档查询操作。
示例代码
以下是基于 Mongoose 的示例代码:
-- -------------------- ---- ------- -- -- -------- -- ----- -------- - -------------------- -- -- ------- --- --------------------------------------------- -- -- ---- - ---- ----- ----- ---------- - --- ----------------- --------- ------- --------- ------ --- ----- ---------- - --- ----------------- ------ ------- -------- ------- ------- - ----- ------------------------------- ---- ------ - --- ----- ---- - ---------------------- ------------ ----- ---- - ---------------------- ------------ -- -------- ----- ---- - --- ------ --------- -------- --------- ------- --- ----- ---- - --- ------ ------ --- ----- ------ -------- ------ -------- ------- -------- --- -- ------- ------- - ------------------ ----- - -- ----- ----- ---- ----------------- ----- ---------------- --- ------------------ ----- - -- ----- ----- ---- ----------------- ----- ---------------- --- -- --------- -------------- ---- -------- -- ------------------- -------------- ----- ----- - -- ----- ----- ---- ------------------ --- -- --------- ---------------- - -------- - ----- -------- ----------- --------- ------------- ------ --- -------- - - ---------------- ----- -------- - -- ----- ----- ---- --------------------- ---
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64ed5304f6b2d6eab3778d7a