You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 10:55:17