Mongoose聚合查询后populate字段,返回结果为undefined求助
问题描述
我已经查阅过相关资料,找到过一篇有帮助的内容,但还是没能解决问题。
我编写了如下查询代码:
const allRequestsFromThisEvent = await Request.aggregate([ { $group: { _id: "$telephone", firstName: { $first: "$firstName" }, lastName: { $first: "$lastName" }, song: { $first: "$song" }, }, }, ]);
该查询返回结果如下:
[ { _id: '+1 (307) 717-8457', firstName: 'Tiago', lastName: 'Pereira', song: new ObjectId("636eca1f91b5d68164c29902") }, { _id: '+1 (533) 427-4934', firstName: 'Alan', lastName: 'Mcknight', song: new ObjectId("636eca1f91b5d68164c29902") }, { _id: '+1 (955) 668-1608', firstName: 'Mia', lastName: 'Reed', song: new ObjectId("636eca1f91b5d68164c29902") }, { _id: '+1 (273) 598-7287', firstName: 'Garth', lastName: 'Stone', song: new ObjectId("636eca1f91b5d68164c29902") } ]
目前查询结果正常,但我想要填充其中的song字段。
我参考相关示例修改后的代码如下:
const allRequestsFromThisEvent = await Request.aggregate([ { $unwind: "$song" }, { $group: { _id: "$telephone", firstName: { $first: "$firstName" }, lastName: { $first: "$lastName" }, song: { $first: "$song" }, }, }, ]).exec(function (err, song) { Song.populate(song, { path: "song" }, function (err, populatedSong) { console.log(populatedSong); }); });
此时回调函数中console.log输出的populatedSong符合预期,但返回的allRequestsFromThisEvent却为undefined。请问我哪里操作出错了?
问题原因及解决方法
错误原因
你混用了await和回调函数两种异步处理方式:
- 当给
.exec()传入回调函数时,它不会返回Promise,而是直接返回undefined,所以await拿到的结果就是undefined,导致allRequestsFromThisEvent被赋值为undefined。 - 回调里的
populatedSong是异步执行的,外部变量已经提前完成赋值,自然拿不到正确结果。
解决方法
改用纯Promise+await的写法,把聚合和填充拆成两步,代码如下:
// 第一步:执行聚合查询 const aggregatedData = await Request.aggregate([ { $unwind: "$song" }, { $group: { _id: "$telephone", firstName: { $first: "$firstName" }, lastName: { $first: "$lastName" }, song: { $first: "$song" }, }, }, ]); // 第二步:对聚合结果填充song字段 const allRequestsFromThisEvent = await Song.populate(aggregatedData, { path: "song" }); console.log(allRequestsFromThisEvent);
如果习惯链式调用,也可以用.then()的写法:
Request.aggregate([ { $unwind: "$song" }, { $group: { _id: "$telephone", firstName: { $first: "$firstName" }, lastName: { $first: "$lastName" }, song: { $first: "$song" }, }, }, ]) .then(aggregatedData => Song.populate(aggregatedData, { path: "song" })) .then(populatedResult => { console.log(populatedResult); // 这里处理最终结果 }) .catch(error => { console.error(error); });
额外提示
如果你的song字段本身就是单个ObjectId(不是数组),那$unwind步骤其实可以去掉,直接聚合后填充就行,能减少不必要的计算。
内容的提问来源于stack exchange,提问作者Tiago Pereira
相关产品推荐
相关产品推荐

