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

如何在Mongoose嵌套查询结果中为Competition添加isLiked属性

解决方案:为Competition添加isLiked属性

你的问题核心在于异步代码的执行顺序:Like.find是异步操作,你在它的回调还没完成时就执行了return res.json(competitions),这时候isLiked属性还没被赋值,所以返回的结果里没有这个字段。另外你原代码里还有个小笔误——把Competition.find写成了Coin.find,这也会导致查询结果不对。

下面提供几种靠谱的解决方法:

方法1:用async/await重构(最易读维护)

async/await可以让异步代码看起来像同步代码,避免回调地狱,同时保证执行顺序:

// 把路由处理函数改成async函数
app.get('/your-target-route', async (req, res) => {
  try {
    // 1. 查询所有Competition数据
    const competitions = await Competition.find().lean();
    // 2. 查询目标用户的所有点赞记录(请根据实际业务调整查询条件)
    const likes = await Like.find({ 
      // 示例:如果是当前用户的点赞,可写 userId: req.user._id
      // 你原代码里的req.params.id请根据实际场景验证是否正确
    }).lean();
    
    // 把点赞的赛事ID存到Set里,方便快速判断
    const likedCompetitionIds = new Set(likes.map(like => like.competition_id.toString()));
    
    // 3. 为每个赛事添加isLiked属性
    competitions.forEach(competition => {
      competition.isLiked = likedCompetitionIds.has(competition._id.toString());
    });
    
    // 4. 确保赋值完成后再返回结果
    res.json(competitions);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: '服务器内部错误' });
  }
});

方法2:用MongoDB聚合查询(性能最优)

直接在数据库层面完成关联和判断,减少一次数据库查询,效率更高:

Competition.aggregate([
  {
    // 关联Like集合,匹配赛事ID和点赞记录中的赛事ID
    $lookup: {
      from: 'likes', // 注意这里是Like集合的复数名称(MongoDB默认会将模型名转为复数)
      localField: '_id',
      foreignField: 'competition_id',
      as: 'matchedLikes'
    }
  },
  {
    // 添加isLiked字段:如果匹配到点赞记录,值为true,否则为false
    $addFields: {
      isLiked: { $gt: [{ $size: '$matchedLikes' }, 0] }
    }
  },
  {
    // 可选:移除临时的matchedLikes数组,只保留需要的字段
    $project: {
      matchedLikes: 0
    }
  }
]).exec((err, competitions) => {
  if (err) {
    console.error(err);
    return res.status(500).json({ error: '服务器内部错误' });
  }
  res.json(competitions);
});

方法3:修复原回调写法(不推荐,仅作参考)

如果你坚持用回调模式,需要把返回结果的逻辑放到Like.find的回调内部,确保属性赋值完成后再返回:

Competition.find().lean().exec(function (err, competitions) {
  if (err) {
    console.log(err);
    return res.status(500).json({ error: err });
  }
  // 请确认这里的查询条件符合业务需求
  Like.find({ /* 正确的查询条件,比如 userId: req.user._id */ }).lean().exec(function (err, likes) {
    if (err) {
      console.log(err);
      return res.status(500).json({ error: err });
    }
    const likedIds = new Set(likes.map(like => like.competition_id.toString()));
    competitions.forEach(competition => {
      competition.isLiked = likedIds.has(competition._id.toString());
    });
    // 必须在这个回调里返回结果,确保isLiked已赋值
    res.json(competitions);
  });
});

额外提示

  • 原代码里的Coin.find是笔误,一定要改成Competition.find
  • 不要用嵌套forEach判断点赞,时间复杂度会达到O(n*m);用Set存储ID可以把时间复杂度降到O(n+m),效率提升明显

内容的提问来源于stack exchange,提问作者Mahmood Kohansal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:32:28