问题描述
在使用 Mongoose 操作 MongoDB 数据库时,有时会遇到一个问题:当查询或更新字符串类型的数据时,Mongoose 会将其转换成了 JavaScript 中的对象类型,导致查询或更新失败。
例如,假设有一个名为 users
的集合,其中有一个文档如下:
{ "_id": ObjectId("5f0a2c2d6d9e1c1b1c4b6a4d"), "name": "Alice", "age": 25, "skills": ["JavaScript", "Node.js"] }
如果我们想要查询名字为 "Alice" 的用户,可以这样写代码:
const name = "Alice"; User.findOne({ name }, (err, user) => { if (err) { console.error(err); return; } console.log(user); });
但是,当我们使用 Mongoose 的 populate
方法来填充关联集合数据时,就会遇到问题。
例如,假设有一个名为 posts
的集合,其中有一个文档如下:
{ "_id": ObjectId("5f0a2c2d6d9e1c1b1c4b6a4e"), "title": "My First Post", "content": "Hello, world!", "author": ObjectId("5f0a2c2d6d9e1c1b1c4b6a4d") }
如果我们想要查询所有文章,并填充对应的作者信息,可以这样写代码:
-- -------------------- ---- ------- ------------- ------------------- ----------- ------ -- - -- ----- - ------------------- ------- - ------------------- ---
但是,当我们运行这段代码时,会发现查询出来的文章中的 author
字段并不是我们期望的用户对象,而是一个 JavaScript 对象,其属性名为用户对象的每个字段,属性值为对应的值。例如:
-- -------------------- ---- ------- - ------ ------------------------------------- -------- --- ----- ------ ---------- ------- -------- --------- - ------ ------------------------------------- ------- -------- ------ --- --------- -------------- ---------- - -
这是因为,在填充关联集合数据时,Mongoose 会自动将字符串类型的 ObjectId 转换成 JavaScript 对象类型,导致填充失败。
解决方案
为了解决这个问题,我们需要手动将字符串类型的 ObjectId 转换成 MongoDB 的 ObjectId 类型。Mongoose 提供了一个 Types.ObjectId
方法,可以用来将字符串类型的 ObjectId 转换成 MongoDB 的 ObjectId 类型。
例如,我们可以将上面的填充代码修改为:
-- -------------------- ---- ------- ----- - ----- - - -------------------- ------------- ----------- ----- --------- ------ ------- ------- ----- ------ -------- - ----- ---- -- --------- - ----- ---------- ------ ------- ------- ------- -------- - ----- ---- -- -- ------ - ---- - ----- -- - -- ---------- ----- ---- -- - ---------- - --------------------------- ------ ---- -- -- ----------- ------ -- - -- ----- - ------------------- ------- - ------------------- ---
在填充关联集合数据时,我们可以在 populate
方法的参数中,使用 transform
选项来手动将字符串类型的 ObjectId 转换成 MongoDB 的 ObjectId 类型。例如,上面的代码中,我们使用了以下代码:
transform: (doc, ret) => { ret.author = Types.ObjectId(ret.author); return ret; },
这个函数会在填充关联集合数据之前被调用,将 author
字段从字符串类型的 ObjectId 转换成 MongoDB 的 ObjectId 类型。这样,我们就可以成功填充关联集合数据了。
总结
在使用 Mongoose 操作 MongoDB 数据库时,如果遇到字符串类型的 ObjectId 数据转换失败的问题,可以手动使用 Types.ObjectId
方法将其转换成 MongoDB 的 ObjectId 类型,从而解决问题。
在填充关联集合数据时,建议使用 transform
选项来手动转换数据类型,以避免数据转换失败的问题。同时,建议使用 lean
选项来提高查询效率。
示例代码:https://github.com/mongoose/mongoose/issues/6880
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/660e2373d10417a222e97a1b