如何在用户模式中向好友数组添加用户
本文旨在指导开发者如何在用户接受好友请求后,将其信息添加到对方用户模式的 friends 数组中。文章将讨论避免前端篡改用户ID的措施,并通过 FriendRequest 模型查询好友列表,同时也会介绍如何在接受好友请求时更新用户模式,并强调使用事务以保证数据一致性的重要性。
确保用户ID的安全性
在处理好友请求时,直接从前端获取发送者(sender)ID存在安全风险。恶意用户可以通过修改HTML来伪造发送者ID,从而导致数据不一致或潜在的安全问题。为了避免这种情况,应该从服务器端的会话或身份验证中间件中获取当前用户的ID。
例如,前端表单可以只包含接收者(receiver)的ID:
在后端路由处理程序中,使用身份验证中间件提供的当前用户ID作为发送者:
router.post("/requests", (req, res) => { const { receiver } = req.body; FriendRequest.create({ sender: req.user._id, // 从身份验证中间件获取当前用户ID receiver }).then(() => { res.status(204).send(); }).catch((error) => { res.status(500).send("Error sending friend request"); }); });
这里假设 req.user._id 包含了经过身份验证的用户的ID。你需要根据你使用的身份验证方法调整这部分代码。
通过 FriendRequest 模型查询好友列表
一种更优雅的方式是避免在 User 模型中显式维护 friends 数组。相反,可以通过查询 FriendRequest 模型来获取好友列表。这种方法利用了 FriendRequest 模型中已经存在的 sender 和 status 字段。
例如,要获取当前用户的所有已接受的好友,可以使用以下查询:
FriendRequest .find({sender: req.user._id, status: 'accepted'}) .then((listOfFriends)=>{ console.log(listOfFriends); }) .catch((e)=>{ // handle error })
这种方法的优点是避免了数据冗余,并且在好友关系发生变化时,只需要更新 FriendRequest 模型即可。
更新用户模式中的 friends 数组 (谨慎使用)
如果仍然需要在 User 模型中显式维护 friends 数组,则需要在接受好友请求时更新这两个用户的 friends 数组。
router.post("/requests/:id/accept", async (req, res) => { try { const request = await FriendRequest.findById(req.params.id); request.status = "accepted"; await request.save(); const currentUser = await User.findById(req.user._id); // 获取当前用户 const otherUser = await User.findById(request.receiver); // 获取接收者用户 currentUser.friends.push(request.receiver); otherUser.friends.push(req.user._id); 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"); } });
注意事项:使用事务
在更新多个集合时,务必使用数据库事务来确保数据一致性。如果在更新 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 currentUser = await User.findById(req.user._id).session(session); // 获取当前用户 const otherUser = await User.findById(request.receiver).session(session); // 获取接收者用户 currentUser.friends.push(request.receiver); otherUser.friends.push(req.user._id); 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() 回滚事务,撤销所有更改。
总结
在处理好友请求时,务必注意用户ID的安全性,并考虑使用 FriendRequest 模型查询好友列表,以避免数据冗余。如果需要在 User 模型中显式维护 friends 数组,则务必使用数据库事务来确保数据一致性。选择哪种方法取决于你的具体需求和对数据一致性的要求。
以上是如何在用户模式中向好友数组添加用户的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undress AI Tool
免费脱衣服图片

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Stock Market GPT
人工智能驱动投资研究,做出更明智的决策

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

本文将介绍如何使用JavaScript实现点击图片切换的效果。核心思路是利用HTML5的data-*属性存储备用图片路径,并通过JavaScript监听点击事件,动态切换src属性,从而实现图片切换。本文将提供详细的代码示例和解释,帮助你理解和掌握这种常用的交互效果。

首先检查浏览器是否支持GeolocationAPI,若支持则调用getCurrentPosition()获取用户当前位置坐标,并通过成功回调获取纬度和经度值,同时提供错误回调处理权限被拒、位置不可用或超时等异常,还可传入配置选项以启用高精度、设置超时时间和缓存有效期,整个过程需用户授权并做好相应错误处理。

要创建JavaScript中的重复间隔,需使用setInterval()函数,它会以指定毫秒数为间隔重复执行函数或代码块,例如setInterval(()=>{console.log("每2秒执行一次");},2000)会每隔2秒输出一次消息,直到通过clearInterval(intervalId)清除,实际应用中可用于更新时钟、轮询服务器等场景,但需注意最小延迟限制、函数执行时间影响,并在不再需要时及时清除间隔以避免内存泄漏,特别是在组件卸载或页面关闭前应清理,确保

本文旨在解决JavaScript中通过document.getElementById()获取DOM元素时返回null的问题。核心在于理解脚本执行时机与DOM解析状态。通过正确放置标签或利用DOMContentLoaded事件,可以确保在元素可用时再尝试访问,从而有效避免此类错误。

Nuxt3的CompositionAPI核心用法包括:1.definePageMeta用于定义页面元信息,如标题、布局和中间件,需在中直接调用,不可置于条件语句中;2.useHead用于管理页面头部标签,支持静态和响应式更新,需与definePageMeta配合实现SEO优化;3.useAsyncData用于安全地获取异步数据,自动处理loading和error状态,支持服务端和客户端数据获取控制;4.useFetch是useAsyncData与$fetch的封装,自动推断请求key,避免重复请

使用ClipboardAPI的writeText方法可复制文本到剪贴板,需在安全上下文和用户交互中调用,支持现代浏览器,旧版可用execCommand降级处理。

本教程详细讲解如何在JavaScript中将数字格式化为固定两位小数的字符串,即使是整数也能显示为"#.00"的形式。我们将重点介绍Number.prototype.toFixed()方法的使用,包括其语法、功能、示例代码以及需要注意的关键点,如其返回类型始终为字符串。

thebestatoreateamulti-linestlinginjavascriptsisisingsistisingtemplatalalswithbacktticks,whatpreserveticks,whatpreservereakeandeexactlyaswrite。
