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

如何实现单用户仅能点赞帖子一次?Node.js+MongoDB开发场景

解决单用户重复点赞问题的方案

我来帮你搞定这个重复点赞的问题,核心思路就是在后端先校验用户是否已经点赞过目标帖子,同时可以优化前端交互提升用户体验,具体实现如下:


1. 后端接口修改(核心校验逻辑)

目前你的接口直接将用户ID加入点赞数组,没有做重复校验。我们需要在添加点赞前,先检查当前用户是否已经出现在该帖子的点赞列表中:

修改后的server.js点赞接口代码:

app.post('/likes/:id', async (req, res) => { 
  try { 
    const post = await Post.findById(req.params.id); 

    // 关键:检查当前用户是否已经点赞过该帖子
    // 注意要把ObjectId转成字符串再对比,避免类型不匹配
    const hasAlreadyLiked = post.likes.some(like => like.user.toString() === req.user.id);

    if (hasAlreadyLiked) {
      // 已经点赞过,直接重定向,不执行后续操作
      return res.redirect('/cogfeed');
    }

    // 未点赞过,才添加到点赞数组
    post.likes.unshift({ user: req.user.id }); 
    await post.save(); 
    res.redirect('/cogfeed'); 
  } catch (err) { 
    console.log(err.message); 
    res.status(500).send('Server Error') 
  } 
})

额外优化:数据库层面防重复

可以给帖子模型的点赞数组添加唯一索引,从数据库层面避免重复点赞数据:

// 帖子模型中的点赞数组定义
likes: [{ 
  user: { 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'users',
    unique: true // 添加唯一约束,同一个用户只能出现在该数组一次
  } 
}]

⚠️ 注意:这个索引需要配合后端的校验一起用,不然重复添加时数据库会抛出错误,后端提前校验可以避免这种情况。


2. 前端交互优化(提升用户体验)

现在前端点击按钮后直接刷新页面,也没有反馈用户是否已经点赞。我们可以优化两点:

  • 渲染时根据用户点赞状态,改变按钮的文本和禁用状态
  • 点击后无需刷新页面,直接更新UI

模板渲染优化(以Handlebars为例)

先注册一个Handlebars辅助函数,用来判断当前用户是否点赞:

// 注册辅助函数,判断用户是否已点赞
handlebars.registerHelper('hasLiked', function(likesList, currentUserId) {
  return likesList.some(like => like.user.toString() === currentUserId);
});

然后修改模板代码,动态渲染按钮状态:

<div> 
  <button 
    class="likesButton btn btn-dark {{#if (hasLiked this.likes currentUser._id)}}liked{{/if}}" 
    id="{{this._id}}"
    {{#if (hasLiked this.likes currentUser._id)}}disabled{{/if}}
  >
    {{#if (hasLiked this.likes currentUser._id)}}已点赞{{else}}点赞{{/if}}
  </button> 
  <span> {{ this.likes.length }} </span> 
</div>

(这里假设你能在模板中访问当前登录用户的currentUser对象)

前端点击事件优化

去掉页面刷新,直接更新按钮状态和点赞数:

<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.js" integrity="sha256-bd8XIKzrtyJ1O5Sh3Xp3GiuMIzWC42ZekvrMMD4GxRg=" crossorigin="anonymous"></script>
<script> 
const likesButtons = document.querySelectorAll('.likesButton'); 
likesButtons.forEach(likeButton => { 
  likeButton.addEventListener('click', async () => { 
    try {
      await axios.post(`/likes/${likeButton.id}`); 
      // 直接更新UI,无需刷新页面
      likeButton.textContent = '已点赞';
      likeButton.disabled = true;
      const likeCountSpan = likeButton.nextElementSibling;
      likeCountSpan.textContent = parseInt(likeCountSpan.textContent) + 1;
    } catch (err) {
      console.error(err);
      alert('你已经点赞过这篇帖子了');
    }
  }); 
}); 
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:37:27