如何在 Mongoose 和 Node.js 中使用 Populate
在开发 MERN 堆栈项目时,我遇到了一种情况:我想填充一个字段,同时还要填充该字段内的另一个字段(我知道这很令人困惑。请耐心等待 :p)。所以,我解决了这个问题,并决定与大家分享。这个想法很棒,不是吗?那就开始吧!
我假设你已经了解 Mongoose、MongoDB 和 Node.js 的基础知识。在本文中,我将介绍 Populate 函数。它是什么,它是如何工作的,以及如何使用它来填充 MongoDB 中的文档。
什么是人口??
填充是一种自动用其他集合中的实际文档替换文档中路径的方法。例如,用用户的数据替换文档中的用户 ID。Mongoose 有一个很棒的方法populate
可以帮助我们。我们refs
在自己的 schema 中定义,Mongoose 会使用这些引用在其他集合中查找文档。
关于填充的一些要点:
- 如果没有找到要填充的文档,则字段将为
null
。 - 对于文档数组,如果未找到文档,则它将是一个空数组。
- 您可以链接填充方法来填充多个字段。
- 如果两种填充方法填充相同的字段,则第二种填充方法将覆盖第一种填充方法。
首先,我们需要一个例子来说明!
我们将创建具有 3 种模式的 3 个集合:
- 用户
- 博客
- 评论
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: String,
email: String,
blogs: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Blog"
}]
});
const BlogSchema = new Schema({
title: String,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
body: String,
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}]
})
const CommentSchema = new Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
blog: {
type: mongoose.Schema.Types.ObjectId,
ref: "Blog"
},
body: String
})
const User = mongoose.model("Author", UserSchema);
const Blog = mongoose.model("Blog", BlogSchema);
const Comment = mongoose.model("Comment", CommentSchema);
module.exports = {User, Blog, Comment}
引用其他模式的最小模式将帮助我们使用填充方法。
Populate 的工作原理
现在让我们看看 populate 是如何工作的。我不会写完整的代码,只写重要的部分。
假设你想通过 ID 获取用户及其博客。如果不填充,你将获得用户文档及其博客 ID 数组。但我们想要的是博客文档,而不是 ID!
那么让我们看看如何做。
// in your node js file
const User = require("path/to/userSchema");
User
.findOne({_id: userId })
.populate("blogs") // key to populate
.then(user => {
res.json(user);
});
/*
OUTPUT:
{
_id: userid, // obviously it will be id generated by mongo
name: "john doe",
email: "john@email.com",
blogs: [
{
_id: blogid,
title: "how to do nothing",
body: "Interesting matter in 11111the blog...",
comments: [commentId_1, commentId_2]
}
]
}
*/
很简单吧?Populate 非常适合像这样合并文档。你将获得 blogs 数组中所有博客文档的用户信息。
但是如果你查看输出,你会发现 comments 数组中仍然充满了评论 ID,而不是来自评论的文档。我们该如何填充它们呢?继续阅读以了解更多……
在文档中嵌套填充!
让我们看看如何在查询中进行嵌套填充以及如何在用户博客中填充评论。
User
.findOne({_id: userId })
.populate({
path: "blogs", // populate blogs
populate: {
path: "comments" // in blogs, populate comments
}
})
.then(user => {
res.json(user);
});
/*
OUTPUT:
{
_id: userid, // obviously it will be id generated by mongo
name: "john doe",
email: "john@email.com",
blogs: [
{
_id: blogid,
title: "how to do nothing",
body: "Interesting matter in the blog...",
comments: [
{
user: userId,
blog: blogId,
body: "your blog is awesome !"
}
]
}
]
}
*/
就是这样。如果要在填充时选择特定字段,可以使用select
key 来指定对象内的字段。
// simple populate
User
.findOne({_id: userId })
.populate("blogs", { name: 1 }) // get name only
// nested populate
User
.findOne({_id: userId})
.populate({
path: "blogs",
populate: {
path: "comments",
select: { body: 1 }
}
})
额外:保存后填充!?
有时(很少),你可能希望在将文档保存到 MongoDB 后填充数据。例如,你创建了一条新评论并保存了它,但在发送响应时,你希望在其中添加用户信息,而不仅仅是用户 ID。
const Comment = require("/path/to/commentSchema");
let newComment = new Comment({
user: userId,
blog: blogId,
body: "this is a new comment"
});
newComment.save().then(result => {
Comment
.populate(newComment, { path: "user" })
.then(comment => {
res.json({
message: "Comment added",
comment
});
})
})
/*
OUTPUT: Comment
{
user: {
_id: userid,
name: "john doe",
email: "johndoe@email.com",
blogs: [blogId_1, blogId_2
},
blog: blogId,
body: "your blog is awesome !"
}
*/
非常感谢您的任何建议。
希望您发现它有用并且从中学到一些新的东西。
祝您编码愉快 :)
如果您想学习 MongoDB,请查看我的学习 MongoDB 系列
文章来源:https://dev.to/paras594/how-to-use-populate-in-mongoose-node-js-mo0