0

0

在Mongoose中实现好友关系:更新User Schema中的好友数组

碧海醫心

碧海醫心

发布时间:2025-09-28 16:10:19

|

586人浏览过

|

来源于php中文网

原创

在mongoose中实现好友关系:更新user schema中的好友数组

本文旨在指导开发者如何在Mongoose中实现用户添加好友的功能,重点讲解在接受好友请求后如何正确更新User Schema中的好友数组。同时,文章也会探讨更高效的数据结构设计方案,以及在使用事务时需要注意的关键点,确保数据一致性。

安全地处理好友请求

首先,确保在处理好友请求时,发送者ID来自已验证的用户会话,而不是直接从前端表单获取。从前端获取用户ID存在安全风险,用户可以通过开发者工具篡改表单数据,冒充他人发送请求。

推荐的做法是从服务器端的会话或身份验证中间件中获取当前用户的ID。以下是修改后的前端表单和后端路由示例:

前端表单 (修改后):

后端路由 (修改后):

router.post("/requests", (req, res) => {
  const { receiver } = req.body;

  FriendRequest.create({
    sender: req.user._id, // 从已验证的用户会话中获取 sender ID
    receiver,
  })
    .then(() => {
      res.status(204).send();
    })
    .catch((error) => {
      res.status(500).send("Error sending friend request");
    });
});

在这个修改后的代码中,req.user._id 代表当前已验证用户的ID,你需要根据你使用的身份验证中间件来调整获取用户ID的方式。

更新User Schema中的好友数组

当用户接受好友请求时,需要更新双方的 User Schema,将对方的 _id 添加到各自的 friends 数组中。以下是更新 User Schema 的代码示例:

router.post("/requests/:id/accept", async (req, res) => {
  try {
    const request = await FriendRequest.findById(req.params.id);
    request.status = "accepted";
    await request.save();

    const currentUserId = req.user._id; // 获取当前用户ID
    const currentUser = await User.findById(currentUserId);
    const otherUser = await User.findById(request.sender);

    currentUser.friends.push(request.receiver);
    otherUser.friends.push(currentUserId);

    await currentUser.save();
    await otherUser.save();

    res.redirect("/requests");
  } catch (error) {
    console.error("Error accepting friend request:", error);
    res.status(500).send("Error accepting friend request");
  }
});

注意事项:

2088shop商城购物系统
2088shop商城购物系统

2088shop商城购物系统是商城系统中功能最全的一个版本:非会员购物、商品无限级分类、不限商品数量、商品多级会员定价、上货库存、Word在线编辑器、订单详情销售报表、商品评论、留言簿、管理员多级别、VIP积分、会员注册积分奖励、智能新闻发布、滚动公告、投票调查、背景图片颜色更换、店标上传、版权联系方式修改、背景音乐(好歌不断)、广告图片支持Flash、弹出浮动广告、搜索引擎关健词优化、图文友情联

下载
  • 在更新 friends 数组之前,请确保 request.receiver 和 currentUserId 都是有效的 ObjectId 类型。
  • 在生产环境中,需要添加错误处理机制,以便在发生错误时能够及时发现并处理。

使用事务保证数据一致性

直接修改两个不同的集合(FriendRequest 和 User)可能导致数据不一致。例如,如果服务器在更新 FriendRequest 集合后崩溃,但尚未更新 User 集合,则会导致数据不一致。为了解决这个问题,可以使用 Mongoose 的事务功能。

以下是使用事务的代码示例:

const mongoose = require('mongoose');

router.post("/requests/:id/accept", async (req, res) => {
  const session = await mongoose.startSession();
  session.startTransaction();

  try {
    const request = await FriendRequest.findById(req.params.id).session(session);
    request.status = "accepted";
    await request.save({ session });

    const currentUserId = req.user._id; // 获取当前用户ID
    const currentUser = await User.findById(currentUserId).session(session);
    const otherUser = await User.findById(request.sender).session(session);

    currentUser.friends.push(request.receiver);
    otherUser.friends.push(currentUserId);

    await currentUser.save({ session });
    await otherUser.save({ session });

    await session.commitTransaction();
    session.endSession();

    res.redirect("/requests");
  } catch (error) {
    await session.abortTransaction();
    session.endSession();
    console.error("Error accepting friend request:", error);
    res.status(500).send("Error accepting friend request");
  }
});

关键点:

  • mongoose.startSession() 创建一个新的会话。
  • session.startTransaction() 启动一个事务。
  • 在查询和保存文档时,使用 .session(session) 将操作与事务关联。
  • session.commitTransaction() 提交事务,所有操作都将永久保存到数据库。
  • session.abortTransaction() 回滚事务,所有操作都将撤销。
  • session.endSession() 结束会话。

更高效的数据结构设计

虽然在 User Schema 中维护一个 friends 数组是常见的做法,但它可能不是最有效的方法,尤其是在用户拥有大量好友的情况下。

另一种更高效的方法是只维护 FriendRequest 集合,并通过查询来获取好友列表。例如:

FriendRequest.find({
  $or: [
    { sender: req.user._id, status: "accepted" },
    { receiver: req.user._id, status: "accepted" },
  ],
})
  .populate("sender receiver") // 可选:填充用户数据
  .then((friendRequests) => {
    const friends = friendRequests.map((request) => {
      return request.sender._id.equals(req.user._id)
        ? request.receiver
        : request.sender;
    });
    console.log(friends);
  })
  .catch((e) => {
    // handle error
  });

这种方法的优点是不需要在多个集合中维护数据,从而避免了数据不一致的问题。缺点是每次获取好友列表都需要执行查询。

总结

在 Mongoose 中实现好友关系需要仔细考虑数据一致性和性能。使用事务可以确保数据一致性,但会增加代码的复杂性。选择合适的数据结构取决于具体的应用场景和性能要求。在开发过程中,请始终关注安全性,并避免从前端获取敏感数据

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

178

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

213

2025.12.18

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

308

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

740

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

88

2025.08.19

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

535

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

17

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

21

2026.01.06

PS使用蒙版相关教程
PS使用蒙版相关教程

本专题整合了ps使用蒙版相关教程,阅读专题下面的文章了解更多详细内容。

23

2026.01.19

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 8.9万人学习

CSS3 教程
CSS3 教程

共18课时 | 4.7万人学习

Vue 教程
Vue 教程

共42课时 | 6.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号