Next.js 中使用 MongoDB 完整指南

1. 安装依赖

npm install mongodb
# 或者使用 mongoose(ODM)
npm install mongoose

2. 数据库连接配置

使用原生 MongoDB 驱动

创建 lib/mongodb.js 文件:

import { MongoClient } from 'mongodb'const uri = process.env.MONGODB_URI
const options = {}let client
let clientPromiseif (process.env.NODE_ENV === 'development') {// 开发环境中使用全局变量避免重复连接if (!global._mongoClientPromise) {client = new MongoClient(uri, options)global._mongoClientPromise = client.connect()}clientPromise = global._mongoClientPromise
} else {// 生产环境中每次创建新连接client = new MongoClient(uri, options)clientPromise = client.connect()
}export default clientPromise

环境变量 .env.local

MONGODB_URI=mongodb://localhost:27017/myapp
# 或者 MongoDB Atlas
MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/database

3. API 路由中的基本操作

创建基础的数据库操作函数

创建 lib/db.js

import clientPromise from './mongodb'export async function connectToDatabase() {const client = await clientPromiseconst db = client.db('myapp') // 数据库名称return { client, db }
}

4. 增加数据(Create)

插入单条记录

创建 pages/api/users/create.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'POST') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')// 插入单条记录const newUser = {name: req.body.name,email: req.body.email,age: req.body.age,createdAt: new Date()}const result = await collection.insertOne(newUser)res.status(201).json({success: true,insertedId: result.insertedId,data: { ...newUser, _id: result.insertedId }})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

使用示例:

// 前端调用
const createUser = async () => {const response = await fetch('/api/users/create', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({name: 'John Doe',email: 'john@example.com',age: 30})})const result = await response.json()console.log(result)
}

插入多条记录

创建 pages/api/users/create-many.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'POST') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')// 插入多条记录const users = req.body.users.map(user => ({...user,createdAt: new Date()}))const result = await collection.insertMany(users)res.status(201).json({success: true,insertedCount: result.insertedCount,insertedIds: result.insertedIds})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

5. 查询数据(Read)

查询所有记录

创建 pages/api/users/index.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'GET') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')// 查询所有记录const users = await collection.find({}).toArray()res.status(200).json({success: true,count: users.length,data: users})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

查询单条记录

创建 pages/api/users/[id].js

import { connectToDatabase } from '../../../lib/db'
import { ObjectId } from 'mongodb'export default async function handler(req, res) {const { id } = req.queryif (req.method === 'GET') {try {const { db } = await connectToDatabase()const collection = db.collection('users')// 通过 _id 查询单条记录const user = await collection.findOne({ _id: new ObjectId(id) })if (!user) {return res.status(404).json({ success: false, message: 'User not found' })}res.status(200).json({success: true,data: user})} catch (error) {res.status(500).json({ success: false, error: error.message })}}
}

条件查询

创建 pages/api/users/search.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'GET') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')const { name, email, minAge, maxAge, page = 1, limit = 10 } = req.query// 构建查询条件let query = {}// 模糊查询名称if (name) {query.name = { $regex: name, $options: 'i' }}// 精确查询邮箱if (email) {query.email = email}// 年龄范围查询if (minAge || maxAge) {query.age = {}if (minAge) query.age.$gte = parseInt(minAge)if (maxAge) query.age.$lte = parseInt(maxAge)}// 分页const skip = (parseInt(page) - 1) * parseInt(limit)// 执行查询const users = await collection.find(query).sort({ createdAt: -1 }) // 按创建时间倒序.skip(skip).limit(parseInt(limit)).toArray()// 获取总数const total = await collection.countDocuments(query)res.status(200).json({success: true,data: users,pagination: {page: parseInt(page),limit: parseInt(limit),total,pages: Math.ceil(total / parseInt(limit))}})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

查询特定字段

创建 pages/api/users/names.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'GET') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')// 只查询 name 和 email 字段,排除 _idconst users = await collection.find({}, { projection: { name: 1, email: 1, _id: 0 } }).toArray()res.status(200).json({success: true,data: users})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

6. 更新数据(Update)

更新单条记录

pages/api/users/[id].js 中添加 PUT 方法:

import { connectToDatabase } from '../../../lib/db'
import { ObjectId } from 'mongodb'export default async function handler(req, res) {const { id } = req.queryif (req.method === 'PUT') {try {const { db } = await connectToDatabase()const collection = db.collection('users')const updateData = {...req.body,updatedAt: new Date()}// 移除不能更新的字段delete updateData._iddelete updateData.createdAt// 更新单条记录const result = await collection.updateOne({ _id: new ObjectId(id) },{ $set: updateData })if (result.matchedCount === 0) {return res.status(404).json({ success: false, message: 'User not found' })}// 返回更新后的数据const updatedUser = await collection.findOne({ _id: new ObjectId(id) })res.status(200).json({success: true,modifiedCount: result.modifiedCount,data: updatedUser})} catch (error) {res.status(500).json({ success: false, error: error.message })}}
}

更新多条记录

创建 pages/api/users/update-many.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'PUT') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')const { filter, update } = req.body// 批量更新记录const result = await collection.updateMany(filter,{ $set: {...update,updatedAt: new Date()}})res.status(200).json({success: true,matchedCount: result.matchedCount,modifiedCount: result.modifiedCount})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

使用示例:

// 将所有年龄小于18的用户状态设为未成年
const updateMinors = async () => {const response = await fetch('/api/users/update-many', {method: 'PUT',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({filter: { age: { $lt: 18 } },update: { status: 'minor' }})})const result = await response.json()console.log(result)
}

7. 删除数据(Delete)

删除单条记录

pages/api/users/[id].js 中添加 DELETE 方法:

export default async function handler(req, res) {const { id } = req.queryif (req.method === 'DELETE') {try {const { db } = await connectToDatabase()const collection = db.collection('users')// 删除单条记录const result = await collection.deleteOne({ _id: new ObjectId(id) })if (result.deletedCount === 0) {return res.status(404).json({ success: false, message: 'User not found' })}res.status(200).json({success: true,deletedCount: result.deletedCount,message: 'User deleted successfully'})} catch (error) {res.status(500).json({ success: false, error: error.message })}}
}

删除多条记录

创建 pages/api/users/delete-many.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'DELETE') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')const { filter } = req.body// 批量删除记录const result = await collection.deleteMany(filter)res.status(200).json({success: true,deletedCount: result.deletedCount,message: `${result.deletedCount} users deleted successfully`})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

8. 高级查询操作

聚合查询

创建 pages/api/users/statistics.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'GET') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')// 聚合查询示例const statistics = await collection.aggregate([{$group: {_id: null,totalUsers: { $sum: 1 },averageAge: { $avg: '$age' },minAge: { $min: '$age' },maxAge: { $max: '$age' }}}]).toArray()// 按年龄分组统计const ageGroups = await collection.aggregate([{$group: {_id: {$switch: {branches: [{ case: { $lt: ['$age', 18] }, then: 'minor' },{ case: { $lt: ['$age', 65] }, then: 'adult' },{ case: { $gte: ['$age', 65] }, then: 'senior' }],default: 'unknown'}},count: { $sum: 1 }}}]).toArray()res.status(200).json({success: true,data: {statistics: statistics[0],ageGroups}})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

文本搜索

创建 pages/api/users/text-search.js

import { connectToDatabase } from '../../../lib/db'export default async function handler(req, res) {if (req.method !== 'GET') {return res.status(405).json({ message: 'Method not allowed' })}try {const { db } = await connectToDatabase()const collection = db.collection('users')const { q } = req.query // 搜索关键词if (!q) {return res.status(400).json({ success: false, message: 'Search query required' })}// 首先需要创建文本索引// await collection.createIndex({ name: 'text', email: 'text' })// 执行文本搜索const users = await collection.find({ $text: { $search: q } }).sort({ score: { $meta: 'textScore' } }).toArray()res.status(200).json({success: true,query: q,count: users.length,data: users})} catch (error) {res.status(500).json({ success: false, error: error.message })}
}

9. 在组件中使用

React 组件示例

// components/UserList.js
import { useState, useEffect } from 'react'export default function UserList() {const [users, setUsers] = useState([])const [loading, setLoading] = useState(true)const [newUser, setNewUser] = useState({ name: '', email: '', age: '' })// 获取用户列表const fetchUsers = async () => {try {const response = await fetch('/api/users')const result = await response.json()if (result.success) {setUsers(result.data)}} catch (error) {console.error('Error fetching users:', error)} finally {setLoading(false)}}// 创建用户const createUser = async (e) => {e.preventDefault()try {const response = await fetch('/api/users/create', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify(newUser)})const result = await response.json()if (result.success) {setUsers([...users, result.data])setNewUser({ name: '', email: '', age: '' })}} catch (error) {console.error('Error creating user:', error)}}// 删除用户const deleteUser = async (id) => {if (!confirm('确定要删除这个用户吗?')) returntry {const response = await fetch(`/api/users/${id}`, {method: 'DELETE'})const result = await response.json()if (result.success) {setUsers(users.filter(user => user._id !== id))}} catch (error) {console.error('Error deleting user:', error)}}useEffect(() => {fetchUsers()}, [])if (loading) return <div>Loading...</div>return (<div><h2>User Management</h2>{/* 创建用户表单 */}<form onSubmit={createUser}><inputtype="text"placeholder="Name"value={newUser.name}onChange={(e) => setNewUser({...newUser, name: e.target.value})}required/><inputtype="email"placeholder="Email"value={newUser.email}onChange={(e) => setNewUser({...newUser, email: e.target.value})}required/><inputtype="number"placeholder="Age"value={newUser.age}onChange={(e) => setNewUser({...newUser, age: parseInt(e.target.value)})}required/><button type="submit">Create User</button></form>{/* 用户列表 */}<div>{users.map(user => (<div key={user._id} style={{ border: '1px solid #ccc', margin: '10px', padding: '10px' }}><h3>{user.name}</h3><p>Email: {user.email}</p><p>Age: {user.age}</p><button onClick={() => deleteUser(user._id)}>Delete</button></div>))}</div></div>)
}

10. 错误处理和最佳实践

统一错误处理

创建 lib/errorHandler.js

export function handleApiError(error, res) {console.error('API Error:', error)if (error.name === 'MongoServerError') {if (error.code === 11000) {// 重复键错误return res.status(400).json({success: false,error: 'Duplicate key error',details: error.keyValue})}}if (error.name === 'CastError') {// ObjectId 格式错误return res.status(400).json({success: false,error: 'Invalid ID format'})}// 通用错误return res.status(500).json({success: false,error: 'Internal server error'})
}

数据验证

创建 lib/validation.js

export function validateUser(userData) {const errors = []if (!userData.name || userData.name.trim().length < 2) {errors.push('Name must be at least 2 characters long')}if (!userData.email || !isValidEmail(userData.email)) {errors.push('Valid email is required')}if (!userData.age || userData.age < 0 || userData.age > 150) {errors.push('Age must be between 0 and 150')}return {isValid: errors.length === 0,errors}
}function isValidEmail(email) {const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/return emailRegex.test(email)
}

这个完整指南涵盖了 Next.js 中使用 MongoDB 的所有基本操作,包括:

  1. 数据库连接配置 - 如何正确配置和管理数据库连接
  2. 增删改查操作 - 完整的 CRUD 操作示例
  3. 条件查询 - 各种查询条件和过滤器的使用
  4. 字段选择 - 如何只查询需要的字段
  5. 分页和排序 - 处理大量数据的最佳实践
  6. 聚合查询 - 复杂的数据统计和分析
  7. 错误处理 - 统一的错误处理机制
  8. 前端集成 - 在 React 组件中如何使用这些 API

每个示例都包含了详细的注释说明,可以根据实际需求进行修改和扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93829.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式系统教学范式演进:云端仿真平台如何重构温湿度监测实验教学

在嵌入式系统开发的教学中&#xff0c;环境温湿度监测实验是经典的入门项目。它涉及传感器原理、外设驱动、数据采集和通信协议等核心知识点。然而传统实验模式面临硬件成本高、调试周期长、设备易损坏等痛点。学生往往因接线错误或代码bug导致传感器或开发板烧毁&#xff0c;不…

1.6万 Star 的流行容器云平台停止开源

什么是 KubeSphere &#xff1f; KubeSphere 是面向云原生应用的容器混合云。 KubeSphere 愿景是打造一个以 Kubernetes 为内核的云原生分布式操作系统&#xff0c;它的架构可以非常方便地使第三方应用与云原生生态组件进行即插即用&#xff08;plug-and-play&#xff09;的集成…

广东省省考备考(第六十三天8.1)——资料分析、数量(强化训练)

资料分析 错题解析解析解析今日题目正确率&#xff1a;80% 数量关系&#xff1a;数学运算 错题解析解析标记题解析解析解析今日题目正确率&#xff1a;87%

Agents-SDK智能体开发[3]之多Agent执行流程

文章目录说明Agents SDK基础Handoffs功能实现Handoffs简单示例&#x1f31f; 运行结果整理&#x1f4dd; 执行过程概述&#x1f4cb; 运行结果事件一&#xff1a;分诊智能体创建转交请求事件事件二&#xff1a;转交响应事件事件三&#xff1a;目标 Agent 响应请求并完成任务改进…

深度揭秘端口映射:原理、场景、路由映射故障,与内网IP端口映射外网工具的选择

内网设备连不上外网&#xff1f;本地网络如何设置端口映射提供互联网服务&#xff1f;路由器端口映射失败怎么办&#xff1f;没有公网IP如何做端口映射&#xff1f;在网络通信领域&#xff0c;端口映射是一项至关重要的技术。在内部网络环境中&#xff0c;每一台设备都被分配了…

协作机器人掀起工厂革命:码垛场景如何用数据重塑制造业命脉?

在长三角某食品包装工厂的深夜生产线上&#xff0c;大视协作码垛机器人正在有序码垛&#xff0c;动作比码垛老师傅更精准。系统推送的实时能耗报表直接显示在厂长手机上&#xff0c;整厂能耗同比下降约32%。这不是魔法&#xff0c;这是"一切数据业务化、业务数据化"在…

LeetCode 刷题【24. 两两交换链表中的节点、25. K 个一组翻转链表】

24. 两两交换链表中的节点 自己做 解&#xff1a;直接置换 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(i…

多线程向设备发送数据

需求:做一个部门授权&#xff0c;可以把所选择部门下面的所有人的人脸信息传到设备组里(多个设备)&#xff0c;问题在于图片是通过Base64处理之后的&#xff0c;会导致文件名非常长&#xff0c;如果一次性传很多数据就会超过设备的最长请求长度&#xff0c;如果不用Base64处理的…

Buck的Loadline和DVS区别和联系

Buck 电路设计中&#xff0c;有两个概念&#xff0c;一个是Load-Line&#xff0c;一个是DVS&#xff0c;它们的含义是什么呢。 Load-Line&#xff08;也称为有源电压定位&#xff0c;AVP&#xff09;是通过调整BUCK电路的输出电压&#xff0c;使其根据负载电流动态变化的技术。…

MySQL会话连接数消耗内存分析

关于连接数消耗内存情况 FROM DEEPSEEK 在 MySQL 中&#xff0c;每个单独的空闲连接所消耗的内存量取决于多个因素&#xff0c;包括连接的线程栈大小&#xff08;由 thread_stack 参数设置&#xff09;和其他每个连接的缓冲区。根据测试结果来看&#xff0c;对于空闲连接的内…

Objective-C实现调节笔记本屏幕亮度(附完整源码)

Objective-C实现调节笔记本屏幕亮度 在macOS上,您可以使用Objective-C来调节笔记本的屏幕亮度。以下是一个简单的示例,演示如何使用CoreGraphics框架来实现这一功能。请确保您的Xcode项目中包含CoreGraphics框架。 完整源码示例 #import <Cocoa/Cocoa.h> #import <…

三十一、【Linux网站服务器】搭建httpd服务器演示个人主页、用户认证、https加密网站配置

httpd服务器功能演示一、安装 HTTPD 服务二、配置个人用户主页1. 启用个人空间功能2. 创建测试用户及网站目录3. 配置 SELinux 权限三、配置用户认证1. 创建密码文件2. 配置目录认证3. 重启服务生效四、配置 SSL 加密网站1. 生成自签名证书2. 配置 SSL 虚拟主机3. 重启服务验证…

把Java程序部署到本地Docker

一&#xff1a;clean && install程序install之后会在target中生成jar包 二&#xff1a;准备三个文件&#xff08;1&#xff09;其中Dockerfile主要起到配置作用&#xff1a;# 基础镜像 FROM openjdk:17-jdk-slim # 作者 MAINTAINER "" # 配置 ENV PAR…

Java学习-------外观模式

在软件开发中&#xff0c;随着系统的不断迭代&#xff0c;模块会越来越多&#xff0c;模块之间的依赖关系也会变得错综复杂。这不仅会增加开发难度&#xff0c;还会让系统的维护和扩展变得棘手。而外观模式就像一位 “前台接待员”&#xff0c;为复杂的系统提供一个简洁统一的接…

Go语言-->变量

Go语言–>变量 在 Go 语言中&#xff0c;定义变量有几种常见的方式。下面是一些常见的语法和用法&#xff1a; 1. 使用 var 关键字定义变量 最常见的方式是使用 var 关键字&#xff0c;后面跟上变量名和类型。你也可以为变量赋初值。 基本格式&#xff1a; var variableName…

分布式链路追踪的实现原理

分布式链路追踪系统的实现涉及多个核心技术环节&#xff0c;下面我将从数据采集、上下文传播、存储分析等维度深入解析其工作原理。 一、核心架构组件 1. 系统组成模块 #mermaid-svg-pDlZY54w2Z0Bp1H1 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-si…

Python爬虫实战:研究micawber库相关技术构建网页采集系统

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上的数据量呈现出爆炸式增长。如何从海量的网页数据中提取有价值的信息,成为了一个重要的研究课题。网络爬虫作为一种自动获取网页内容的技术,为解决这一问题提供了有效的手段。通过网络爬虫,可以快速、高效地采集…

前端框架Vue3(三)——路由和pinia

路由的理解 路由就是一组key-value的对应关系&#xff0c;多个路由&#xff0c;需要经过路由器的管理。 路由-基本切换效果 导航区、展示区请来路由器制定路由的具体规则&#xff08;什么路径&#xff0c;对应着什么组件&#xff09;形成一个一个的路由 【两个注意点】 路由组件…

【go】实现BMI计算小程序与GUI/WEB端实现

好的&#xff0c;下面是用 Go 语言实现的一个简单的 BMI&#xff08;Body Mass Index&#xff0c;身体质量指数&#xff09;计算器&#xff0c;包含中文注释与完整代码&#xff0c;可以直接运行。 一、BMI 计算公式 BMI体重&#xff08;kg&#xff09;身高2&#xff08;m2&…

Windows系统优化命令-记录

闲着无聊&#xff0c;近来电脑有些卡顿&#xff0c;记录一下相关命令。最好的命令还是格式化╮(╯▽╰)╭ 1. 磁盘清理相关命令 cleanmgr - 磁盘清理工具 cleanmgr启动磁盘清理工具&#xff0c;可清理临时文件、回收站等内容 diskpart - 磁盘分区工具 diskpart用于磁盘管理&…