我有一个端点执行如下操作:
const pipeline = [
{
$match: {
$and: [
{
$or: [...],
},
],
},
},
{
$group: {
_id : '$someProp',
anotherProp: { $push: '$$ROOT' },
},
},
{ $sort: { date: -1 } },
{ $limit: 10 },
]
const groupedDocs = await MyModel.aggregate(pipeline);
这里的想法是返回的文档看起来像这样:
[
{
_id: 'some value',
anotherProp: [ /* ... array of documents where "someProp" === "some value" */ ],
},
{
_id: 'another value',
anotherProp: [ /* ... array of documents where "someProp" === "another value" */ ],
},
...
]
在得到这些结果之后,端点用一个包含anotherProp
的所有成员的数组来响应,如下所示:
const response = groupedDocs.reduce((docs, group) => docs.concat(group.anotherProp), []);
res.status(200).json(response);
我的问题是响应中的最终文档包含_id
字段,但我想将该字段重命名为id
。This question解决了这个问题,特别是this answer是 * 应该 * 工作的,但由于某种原因转换函数没有被调用。
schema.set('toJSON', {
virtuals: true,
transform: function (doc, ret) {
console.log(`transforming toJSON for document ${doc._id}`);
delete ret._id;
},
});
schema.set('toObject', {
virtuals: true,
transform: function (doc, ret) {
console.log(`transforming toObject for document ${doc._id}`);
delete ret._id;
},
});
但是console.log
语句没有被执行,这意味着转换函数没有被调用,所以我仍然在响应中得到_id
而不是id
。
因此,我的问题是在此场景中如何获得id
而不是_id
?
值得一提的是,toJSON
和toObject
在我从文档读取属性的其他地方被调用(console.log
s显示)。
const doc = await MyModel.findById('someId');
const name = doc.name;
res.status(200).json(doc);
响应包含id
而不是_id
,这几乎就像我对文档执行任何操作时都会调用transform函数一样,但是如果在文档从数据库到达时直接传递文档,则toJSON
和toObject
都不会被调用。
提前感谢你的见解。:)
2条答案
按热度按时间mcdcgff01#
toJSON
和toObject
方法在这里不起作用,因为它们不适用于来自聚合管道的文档。Mongoose不会将聚合文档转换为mongoose文档,它返回管道操作返回的原始对象。我最终通过添加管道阶段来实现这一点,首先添加一个id
字段,该字段的值与_id
字段的值相同。然后第二步删除_id
字段。所以我的流水线基本上变成了:s5a0g9ez2#
从聚合中获取原始对象后,可以将其重新转换为mongoose文档,只需将它们逐个转换回来,它们将在返回时触发
toJSON
。答案在这里找到:Cast plain object to mongoose document