给mongoose find()/findOne()查询的结果添加额外的属性
在学习 mongoose 的时候,碰到一个需要注意的地方。
给查询结果添加额外的属性时,不能直接在这个结果对象上添加属性。原因和解决方案往下看。
假设 User 集合有一个 name 字段:
const User = new mongoose.Schema({ 'name': String });
(添加一些数据)加上它附带的 _id 字段,应该如下:
> User.find().pretty();
//结果
[
{
"_id": ObjectId("62449223fb0988f6c2cecf3d"),
"name": 'wffw'
},
{
"_id": ObjectId("62449223fbca2354d3daf8fca"),
"name": 'luyu'
},
……
]
当我查询结果之后,想要添加一个属性给每一个结果时候,神奇的一幕发生了!
User.find().then((list) => {
list.map((item, index) => {
console.log('1---', item); // (1)
item.str = '给item添加一个 str 属性。'; // (2)
console.log('2---', item); // (3)
})
})
// 结果
1--- [
{
"_id": ObjectId("62449223fb0988f6c2cecf3d"),
"name": 'wffw'
},
……
]
2--- [
{
"_id": ObjectId("62449223fb0988f6c2cecf3d"),
"name": 'wffw'
},
……
]
上面 (3) 输出的结果出乎我意料,和 (1) 的结果一模一样,没有发现 str 属性,我的 str 呢?(遇事不决,量子力学?)
这当然不是量子问题。会不会是 这个 item 是只读的,(2)处根本没有赋值成功? 既然如此,那就不直接操作 item ,创建一个新的对象试试(方式一):
User.find().then((list) => {
list.map((item, index) => {
let one = {
_id: item._id,
name: item.name,
str: '给item添加一个 str 属性。'
}
console.log('4---', item); // (4)
console.log('5---', mylist); // (5)
})
})
// 结果
5--- {
"_id": ObjectId("62449223fb0988f6c2cecf3d"),
"name": 'wffw',
"str": '给item添加一个 str 属性。'
}
// 果然如此呐,哈哈
那么,,,
到这里你以为就结束了? item 真的是只读的吗?事实就是如此的吗?
(真相~ 真香~)
听说过 getOwnPropertyDescriptors() 吧,打印一下 item的属性描述符:
User.find().then((list) => {
list.map((item, index) => {
item.str = '这是一个新的属性';
console.log('6---', item) // (6)
console.log('list[' + index + ']---', Object.getOwnPropertyDescriptors(item)); // (7)
})
})
// 结果
//毋庸置疑,(6) 打印的结果里没有 str。
(7) 打印的结果 会是什么呢?如下:
// (7) 打印的结果:取其中一个:
list[0]--- {
'$__': {
value: InternalCache {
activePaths: [StateMachine],
strictMode: true,
skipId: true,
selected: {},
fields: {},
exclude: null,
_id: new ObjectId("62449223fb0988f6c2cecf3d")
},
writable: true,
enumerable: true,
configurable: true
},
'$isNew': {
value: false,
writable: true,
enumerable: true,
configurable: true
},
_doc: {
value: {
_id: new ObjectId("62449223fb0988f6c2cecf3d"),
name: 'wffw',
__v: 0
},
writable: true,
enumerable: true,
configurable: true
},
str: {
value: '这是一个新的属性',
writable: true,
enumerable: true,
configurable: true
}
}
前两个属性(”$__”、”$isNew”)忽略,仔细看最后两个属性:_doc 里的属性才是 我们cosole.log(item) 的结果!str 并不是没有添加成功,item 并不是只读的!
Emm……#?!$@*……
现在知道了吧,find().then() 或者 findOne().then() 得到的结果,是有一层封装,在获取这个结果的时候,会自动解封,但是 在自己添加属性的时候,不会自动解封。官方说法:
Mongoose models provide several static helper functions for CRUD operations. Each of these functions returns a mongoose `Query` object.
Mongoose模型为CRUD 操作提供了几个静态辅助函数。这些函数中的每一个都返回一个 mongooseQuery
对象。
所以,除了(方式一),还有一种方式,赋给 item._doc (方式二) :
User.find().then((list) => {
list.map((item, index) => {
console.log('8---', item); // (8)
item._doc.str = '给item添加一个 str 属性。';
console.log('9---', item); // (9)
})
})
// (8) 略
// (9) 结果:
1--- [
{
"_id": ObjectId("62449223fb0988f6c2cecf3d"),
"name": 'wffw',
"str": '给item添加一个 str 属性。'
},
……
]
舒服了。
总结: 方式一 和方式二 都可以,推荐方式一,因为这不需要额外知道”_doc”。