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

如何基于Mongoose建模实现用户主页的三种好友状态按钮?

实现用户主页的好友状态按钮:建模与聚合查询方案

我来帮你搞定这个用户主页好友按钮的问题!核心思路是把用户间的好友关系单独建模,再通过聚合查询把状态和目标用户信息绑定,这样就能动态显示对应的按钮了。

一、好友关系建模方案

你现有的User Schema保持不变就好,我们单独创建一个Friendship Schema来管理好友请求的状态——因为用户间的好友关系是双向的,而且有明确的状态(发起、通过),单独建模比在User里存数组要灵活得多,后续维护状态变更也更方便。

const mongoose = require('mongoose');

const friendshipSchema = new mongoose.Schema({
  // 请求发起者ID
  requester: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  // 请求接收者ID
  recipient: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  // 好友状态:pending=已请求,accepted=已成为好友,rejected=已拒绝(可选)
  status: {
    type: String,
    enum: ['pending', 'accepted', 'rejected'],
    default: 'pending',
    required: true
  }
}, { timestamps: true });

// 添加复合唯一索引,避免同一个用户向另一个用户重复发起请求
friendshipSchema.index({ requester: 1, recipient: 1 }, { unique: true });

const Friendship = mongoose.model('Friendship', friendshipSchema);

二、聚合查询:动态获取好友状态

当用户访问目标用户主页时,我们需要在查询目标用户信息的同时,关联当前登录用户与目标用户的好友状态。用MongoDB的聚合查询可以一步完成这个需求:

// 假设当前登录用户ID为 currentUserId,要访问的目标用户ID为 targetUserId
const targetUser = await User.aggregate([
  // 第一步:匹配目标用户的基本信息
  { $match: { _id: mongoose.Types.ObjectId(targetUserId) } },
  // 第二步:关联Friendship集合,查找双方的好友关系
  {
    $lookup: {
      from: 'friendships',
      let: { targetId: '$_id', currentId: mongoose.Types.ObjectId(currentUserId) },
      pipeline: [
        {
          $match: {
            $expr: {
              // 匹配两种情况:当前用户发起请求给目标用户,或者目标用户发起请求给当前用户
              $or: [
                { $and: [{ $eq: ['$requester', '$$currentId'] }, { $eq: ['$recipient', '$$targetId'] }] },
                { $and: [{ $eq: ['$requester', '$$targetId'] }, { $eq: ['$recipient', '$$currentId'] }] }
              ]
            }
          }
        },
        { $project: { status: 1, _id: 0 } } // 只保留状态字段
      ],
      as: 'friendshipStatus'
    }
  },
  // 第三步:把数组格式的状态转为单个值(因为双方最多只有一条好友关系记录)
  {
    $addFields: {
      friendStatus: {
        $cond: {
          if: { $gt: [{ $size: '$friendshipStatus' }, 0] },
          then: { $arrayElemAt: ['$friendshipStatus.status', 0] },
          else: null
        }
      }
    }
  },
  // 第四步:移除临时的friendshipStatus数组字段
  { $project: { friendshipStatus: 0 } }
]);

// 最终targetUser[0]会包含目标用户的基本信息 + friendStatus字段:
// - friendStatus为null:显示「添加好友」按钮
// - friendStatus为'pending':显示「已请求」按钮(如果是当前用户发起的请求)
// - friendStatus为'accepted':显示「已成为好友」按钮

补充业务逻辑提示

  • 点击「添加好友」时:创建一条Friendship记录,requester为当前用户ID,recipient为目标用户ID,状态默认pending。
  • 处理好友请求时:找到对应的Friendship记录,把status改为accepted。
  • 前端渲染按钮时:根据返回的friendStatus值,直接切换对应的按钮文本和样式即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:54:46