1. MongoDB的下载与配置
1.1 下载
使用MongoDB需要下载其对应版本的服务端与客户端
服务端:Mongod
https://www.mongodb.com/try/download/community-kubernetes-operator
客户端:使用Mongosh
MongoDB Shell Download | MongoDB
1.2 配置MongoDB
MongoDB的数据会默认存储在'C:/data/db'中,所以用户需要在C盘中创建data文件夹,其中再创建db文件夹
在MongoDB中包含多个数据库,数据库包含多个集合collection,每一个集合包含了多个文档,在操作mongdb中需要进入到相应的数据库,然后针对于对于collection进行操作
使用MongoDB时,需要保证服务端和客户端同步打开,使用cmd命令行启动
2. 数据库命令
以下是在MongoDB客户端中常见的数据库命令操作:
2.1 数据库操作
显示所有数据库
show dbs
切换数据库
use myDatabase
如果数据库不存在,会在插入数据时自动创建。
db
显示当前所在数据库
use 库名
db.dropDatabase()
删除当前数据库
2.2 集合命令操作
创建集合
db.createCollection('集合名称')
显示当前数据库中所有的集合
show collections
删除集合
db.集合名.drop()
集合重命名
db.集合名.renameCollection('名称')
2.3 文档命令
以myCollection集合为例
插入数据
db.myCollection.insertOne({ name: "Alice", age: 25, city: "New York" })
插入多个文档
db.myCollection.insertMany([
{ name: "Bob", age: 30, city: "San Francisco" },
{ name: "Charlie", age: 35, city: "Los Angeles" }
])
2.4 查询数据
查询所有文档
db.myCollection.find()
按条件查询
db.myCollection.find({ age: { $gt: 25 } }) # 查询年龄大于25的文档
运算符
在mongodb中不能直接使用<,>,<=,>=等符号,需要使用替代符号
> | $gt |
< | $lt |
>= | $gte |
<= | $lte |
!== | $ne |
逻辑运算
逻辑或
db.collectionName.find({$or:[{age:{$lt:30}},{age:{$gt:40}}]})
逻辑与
db.collectionName.find({$and:[{age:{%lt:20}},{age:{$gt:15}}]})
更新数据
db.myCollection.updateOne({ name: "Alice" }, { $set: { age: 26 } })
db.myCollection.updateMany({ city: "New York" }, { $set: { city: "NYC" } })
删除数据
删除单个文档
db.myCollection.deleteOne({ name: "Bob" })
删除多个文档
db.myCollection.deleteMany({ age: { $lt: 30 } }) # 删除年龄小于30的文档
3. 基于Node.js的驱动 - Mongoose
Mongoose是构建在MongoDB驱动之上的更高级的抽象库
简化了复杂查询和数据操作,支持中间件,钩子等高级功能
3.1 连接MongoDB
在javascript中实现操作MongoDB数据库需要与之进行连接,默认端口为27017,下划线后声明操作的数据库名称
mongoose.connect("mongodb://127.0.0.1:27017/test")
设置事件以及相应的回调函数
mongoose.connection.on('open',()=>{console.log('连接成功')});
mongoose.connection.on('error',()=>{console.log('Error')})
mongoose.connection.on('close',()=>{console.log('链接关闭')})
分别为数据库连接事件,连接失败事件,数据库关闭事件,以及对应的回调函数
设置回调关键字也可以使用once,事件回调函数只执行一次
mongoose.connection.once('open',async ()=>{})
async声明一个异步函数,最终会返回一个Promise对象,函数内部可以使用await来等待异步操作完成。
断开数据库连接,在正式运行时一般不使用该操作
mongoose.disconnect()
3.2 创建文档的结构对象
3.2.1 定义构造器
mongoose.Schema是Mongoose提供的一个构造器,用于定义MongoDB集合中文档的结构,以及字段的验证规则
const BookSchema = new mongoose.Schema({
name: { type: String, required: true }, // 书名,类型是字符串,必填
author: { type: String, required: true }, // 作者,类型是字符串,必填
price: { type: Number, required: true }, // 价格,类型是数字,必填
pub_time: { type: Date, required: true }, // 出版时间,类型是日期,必填
});
字段类型
类型 | 描述 |
String | 字符串 |
Number | 数字 |
Boolean | 布尔值 |
Array | 数组 |
Date | 日期 |
Buffer | Buffer对象 |
Mixed | 任意类型,mongoose.Schema.Types.Mixed指定 |
ObjectId | 对象ID,mongoose.Schema.Types.ObjectId指定 |
Decimal128 | 高精度数字, mongoose.Schema.Types.Decimal128指定 |
字段值验证
必填项:
name:{type:String,required:true}
默认值:
name:{type:String, default:'default'}
枚举值:
设置的值必须是数组当中的
name:{type:String,enum:['male','female']}
唯一值:
表示这个值是唯一的,不能产生重复的
name:{type:String, unique:true}
注意:永远不要相信用户的输入!!!
3.2.2 模型对象
模型对象是对MongoDB集合的封装,提供了用于操作集合的方法,增删改查。
const BookModel = mongoose.model("books", BookSchema);
·第一个参数:表示数据库中集合的名称,mongoose会使用集合名称的复数创建集合
·第二个参数:之前所有定义的Schema,用于描述集合中文档的结构
3.3 模型方法
方法中的语句与MongoDB操作语句别无二致,但需要使用到模型对象进行对应操作
插入文档
- 创建文档实例并保存
只会创建一个文档实例,并不会自动将其保存到数据库
const book = new BookModel({数据})
显式调用 save()
方法才能将该实例保存到数据库中
await book.save()
- 快速创建插入
const data = await BookModel.create({
name: "西游记",
author: "吴承恩",
price: 19.9,
pub_time:new Date()
});
删除文档
await BookModel.deleteOne({ name: "红楼梦" }); // 删除匹配的单个文档
await BookModel.deleteMany({name:'西游记'})//删除多个文档
更新文档
await BookModel.updateOne({ name: "西游记" }, { price: 22.0 }); // 更新价格
await BookModel.updateMany({ name: "西游记" }, { price: 22.0 }); // 更新价格
读取文档
const book = await BookModel.findOne({ price: { $gte: 20 } }); // 查找单个价格大于等于20的书
const books = await BookModel.find({price:{$gte:20}}) //批量查找
const books = await BookModel.find();
个性化读取
字段筛选
const results = await BookModel.find({}, "name price"); // 只返回 name 和 price
使用字符串定义需要返回的字段属性
数据排序
Model.find(filter).sort({ field: 1 or -1 })
1表示升序;-1表示降序
数据截取
limit():限制查询结果的数量
const results = await BookModel.find().limit(5); // 获取前 5 条文档
console.log(results);
skip():跳过指定数量的文档,常用于分页查询
const page = 2; // 当前页数
const limit = 3; // 每页显示的文档数量
const results = await BookModel.find()
.skip((page - 1) * limit)
.limit(limit);
console.log(results);
4. 示例:模拟注册登陆系统
4.1 前端页面
login.html:
<!DOCTYPE html>>
<head>
<title>登陆页面</title>
</head>
<body>
<form method="post" action="/dashboard">
<!-- 姓名 -->
<label for="name">姓名</label>
<input type="text" id="name" name="name" placeholder="请输入你的姓名" required><br><br>
<!-- 年龄 -->
<label for="age">年龄</label>
<input type="number" id="age" name="age" placeholder="请输入你的年龄" min="0" required><br><br>
<!-- 提交按钮 -->
<button type="submit">提交</button>
</form>
</body>
register.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Train Page</title>
</head>
<body>
<h1>用户信息注册</h1>
<form method="post" action="/save">
<!-- 姓名 -->
<label for="name">姓名</label>
<input type="text" id="name" name="name" placeholder="请输入你的姓名" required><br><br>
<!-- 年龄 -->
<label for="age">年龄</label>
<input type="number" id="age" name="age" placeholder="请输入你的年龄" min="0" required><br><br>
<!-- 提交按钮 -->
<button type="submit">提交</button>
</form>
</body>
</html>
page.html:
<!DOCTYPE html>
<head>
<title>主页面</title>
</head>
<body>
<h1>欢迎访问主页</h1>
<a href="/login">登录</a>
<a href="/register">注册</a>
</body>
4.2 后端数据存储与验证
const bodyParser = require('body-parser');
const express = require('express');
const mongoose = require('mongoose');
const path = require('path');
const app = express();
// 配置 body-parser
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 连接 MongoDB
mongoose.connect('mongodb://127.0.0.1:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
mongoose.connection.once('open', () => {
console.log('数据库连接成功');
});
// 定义用户 Schema 和模型
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
age: { type: Number, min: 0, required: true },
});
const User = mongoose.model('User', userSchema);
// 主页面
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname,"page.html"));
});
// 注册页面
app.get('/register', (req, res) => {
res.sendFile(path.join(__dirname, 'register.html'));
});
// 登录页面
app.get('/login', (req, res) => {
res.sendFile(path.join(__dirname, 'login.html'));
});
// 保存用户信息
app.post('/save', async (req, res) => {
try {
const { name, age } = req.body;
const newUser = new User({ name, age });
console.log('保存用户:', name, age);
await newUser.save();
res.send('<h1>保存用户成功</h1><a href="/">返回主页</a>');
} catch (err) {
console.error('保存用户失败:', err);
res.status(500).send('<h1>保存失败</h1><a href="/">返回主页</a>');
}
});
// 登录验证
app.post('/dashboard', async (req, res) => {
try {
const { name, age } = req.body;
// 查找用户
const user = await User.findOne({ name });
if (!user) {
return res.status(400).send('<h1>用户不存在</h1><a href="/login">返回登录</a>');
}
// 验证年龄
if (parseInt(age) === user.age) {
res.send('<h1>登录成功</h1><a href="/">返回主页</a>');
} else {
res.status(400).send('<h1>年龄错误,登录失败</h1><a href="/login">返回登录</a>');
}
} catch (err) {
console.error('登录失败:', err);
res.status(500).send('<h1>登录失败</h1><a href="/login">返回登录</a>');
}
});
// 启动服务
app.listen(3000, () => {
console.log('服务启动,监听端口 3000');
});