在 Mongoose 中,Virtuals 和 Populate 是两个非常常用的功能。Virtuals 可以让我们在获取数据时动态生成新的属性,而 Populate 可以让我们在查询时将关联数据一起查询出来。但是,在使用这些功能时也会遇到一些问题。在本文中,我们将介绍如何解决 Virtuals 和 Populate 的常见问题。
Virtuals 的问题解决
问题一:Virtuals 不能被查询
Virtuals 默认情况下是不能被查询的,因为 Virtuals 并不存在于数据库中。但是,我们可以通过设置 virtuals: true
选项来让 Mongoose 返回包含 Virtuals 的查询结果。示例代码如下:
-- -------------------- ---- ------- ----- ------------ - --- -------- ---------- ------- --------- ------ --- ----------------------------------------------- - ------ -------------- - - - - -------------- --- ----- ------ - ------------------------ -------------- --------------- - --------- - -- - --------- ---- -- --------------- -- - --------------------- -- -- --------- ----- ----- ---- ------------------------ -- ---
问题二:Virtuals 的 get 和 set 函数不能被异步执行
虽然 Virtuals 的 get 和 set 函数看起来是普通的 JavaScript 函数,但它们在使用时必须是同步执行的。例如,下面的代码是错误的:
PersonSchema.virtual('firstNameUpper').get(async function() { const upperCaseFirstName = await doSomeAsyncTask(this.firstName); return upperCaseFirstName; });
这是因为 Mongoose 使用的是 Object.defineProperty 来定义 Virtuals,而 Object.defineProperty 不支持异步函数。
解决方法是将异步操作放到 Virtuals 的 set
函数中。例如,我们可以将上面的 Virtuals 修改为以下代码:
PersonSchema.virtual('firstNameUpper') .get(function() { return this.firstName.toUpperCase(); }) .set(async function(val) { this.firstName = await doSomeAsyncTask(val); });
Populate 的问题解决
问题一:Populate 的查询结果嵌套层数过多
Populate 能够让我们在查询时一次性地将多个关联数据查询出来,但是这会导致查询结果的嵌套层数过多,使查询结果难以处理。例如,下面的代码展示了通过多次使用 populate 查询嵌套数据的方式,查询 Order 数据关联的 User 和 Product 数据的问题。
Order.find().populate('user').populate('items.product').exec((err, orders) => { // orders 中包含了大量的嵌套对象 // 例如,orders[0].user.address.city // orders[0].items[0].product.reviews[0].rating });
解决方法是使用 lean
和 objectId
选项避免多层嵌套。lean
选项可以让查询结果变成普通的 JavaScript 对象,而不是 Mongoose 的 Model 实例,这样就能够避免数据的嵌套。objectId
选项可以将关联的 ObjectId 转为字符串,使得查询结果中包含的关联数据与主数据可以分开处理。例如,下面的代码展示了使用 lean
和 objectId
选项处理 Order 数据的查询结果的方式。
-- -------------------- ---- ------- ------------ ----------- ----- ------- ------- ------------ -------- - ----- ----- --------- ---- - -- ---- -------- ----- ---- -------- ----- -- ----------- ----- ---------------- --------- - ----- --------------- ------- ---------- -- -------- - ----- ----- --------- ---- - -- ---- -------- ----- ---- -------- ----- -- ------- ----------- ------- -- - -- ------ ------------------ -- ------------------------------ -- -------------------------------------------- ---
问题二:Populate 只能查询单个字段
默认情况下,Populate 只能查询单个字段。但是,在某些情况下,我们可能需要查询多个字段。例如,在查询文章时需要查询作者的全部信息,包括姓名、邮箱、头像等。此时,我们需要使用自定义查询函数来实现。
示例代码如下:
-- -------------------- ---- ------- -- -- ------- --- ----- ------------- - --- -------- ------ ------- --------- - ----- ---------------------- ---- ------ - --- ----- ------- - ------------------------- --------------- -- -- ---- --- ----- ---------- - --- -------- ----- ------- ------ ------- ------- ------ --- ----- ---- - ---------------------- ------------ -- ---------- ------ ----- ------------------------------------ - ----- ---------- - ----- ------ - ----- ----------------------------- ----------- - ------- ------ ----- -- -- ----------- ----------- ------ ----- --------------------------- --------------- -- ------------------------- ------------------------- -- --------------------------------
总结
Virtuals 和 Populate 是 Mongoose 中非常常用的功能。在使用这些功能时,我们可能会遇到一些问题,例如 Virtuals 不能被查询和 Populate 的查询结果嵌套层数过多等。本文介绍了如何解决这些问题,提供了详细的示例代码。希望本文能够对你在使用 Mongoose 时遇到的问题有所帮助。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64eed09af6b2d6eab38c39d0