非关系型数据库,存储的数据都是 key-value 的形式
安装数据库
mongo
连接数据库,以查看是否安装成功window
+ r
→ 输入 services.msc
打开任务管理器 → 找到 MongoDB 数据库,右键 启动
/ 停止
基本概念
常用命令
show dbs
:查询所有数据库> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
db
:查看当前数据库> db
test
可以看见,当前使用的数据库为 test;但是,因为现在 test 数据库中没有数据,所以不会被 show dbs
查询出来
use 数据库名
:切换数据库;如果找不到该数据库,则会创建该数据库show collections
:展示当前数据库中的表(集合)db.表名.find()
:查询该表中的数据(文档)db.dropDatabase()
:删除当前数据库node.js 的第三方模块 mongoose,用于操作 MongoDB 数据库
npm init -y
npm i mongoose
const mongoose = require('mongoose')
// localhost - 数据库的 ip 地址
// 27017 - MongoDB 的端口号,默认为 27017
// node - 数据库名,表示使用该数据库;没有则自动创建
mongoose.connect('mongodb://localhost:27017/node').then(_ => {
console.log("连接成功!");
}, reason => {
console.log("连接失败!", reason);
});
mongoose.disconnect()
可通过监听
open
&close
事件,来监听数据库的连接与断开
mongoose.connection.once('open', () => {
console.log("数据库已连接");
});
mongoose.connection.once('close', () => {
console.log("数据库已断开");
});
Schema 是 mongoose 的一个方法,可以设计表结构,用于创建 model 模型
MongoDB 支持的数据类型:
添加数据时,如果数据类型写错了,MongoDB 会进行隐式类型转换;如果转换不成功,则抛出错误
MongoDB 没有 Object 类型,如果强行设置为 Object 类型,会转为 Array 类型
// 创建 Schema 实例
const studentSchema = new mongoose.Schema({
name: String,
age: Number,
course: Array,
});
// 创建 Student 集合
const StudentModel = mongoose.model('Student', studentSchema);
配置 Schema
timestamps
:为 true
时,会添加 createdAt
& updatedAt
两个字段,代表 [创建时间] & [更新时间]versionKey
:为 false
时,不会添加版本号 __v
字段const studentSchema = new mongoose.Schema({
name: String,
age: Number,
course: Array,
}, {
timestamps: true,
versionKey: false
});
注意:我们要在创建表时就确定表结构,确定后不要轻易更改!
require
:Boolean;是否必需填写;如果设置为 true,没填写时会抛出错误require: [true, "message"]
:后面的 “message” 是报错信息default
:默认值。可以是函数,如果是函数,则默认值为函数的返回值validate
:自定义验证。有一个 validator
方法 & 一个 message
属性validator
的参数为当前字段;return true
表示通过验证,return false
则抛出错误,错误信息为 message
const studentSchema = new mongoose.Schema({
name: {
type: String,
required: true,
validate: {
validator(name) {
if (name.length <= 5) return true;
return false;
},
message: "name is too long"
}
},
age: {
type: Number,
required: [true, "age is required"],
default: 21
},
course: {
type: Array,
default: ["HTML", "CSS", "JS"]
},
});
lowercase
:Boolean;小写uppercase
:Boolean;大写trim
:Boolean;去除空格minlength
:Number;最小长度maxlength
:Number;最大长度enum
:Array;只能填写 Array 中的元素match
:Regex;需匹配正则const studentSchema = new Schema({
name: {
type: String,
trim: true,
enum: ["superman", "superwoman"]
},
age: Number,
course: Array
});
min
:最小数值max
:最大数值const studentSchema = new Schema({
name: String,
age: {
type: Number,
min: 18
},
course: Array
});
type
:设置数组元素的类型(可用类型参考 MongoDB 支持的数据类型);只设置 type
时可直接写属性值const studentSchema = new Schema({
name: String,
age: Number,
course: [String] // 会将元素隐式转换为 String 类型,转不了则报错
});
minlength
/ maxlength
:设置数组元素的长度const studentSchema = new Schema({
name: String,
age: Number,
course: [{
type: String,
minlength: 4 // 元素的最小长度为 4
}]
});
[]
里面啦~save
StudentModel
,调用 save
方法:new StudentModel({
name: "小陈",
age: 20,
course: ["C++", "Java"]
}).save((err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
打印的数据:
result {
name: '小陈',
age: 20,
course: [ 'C++', 'Java' ],
_id: new ObjectId("622b317092def5225f02c6b7"),
__v: 0
}
可以看见,MongoDB 自动给我们添加了 _id
属性,这是数据的唯一标识
create
model.create(dataObj, (err, result) => {})
StudentModel.create({
name: "小黄",
age: 21,
course: ["HTML", "CSS", "JS"]
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
添加多个数据:
model.create(dataObj1, dataObj2, (err, result1, result2) => {})
StudentModel.create({ // 传入多个对象
name: "小胡",
age: 20,
course: ["MongoDB"]
}, {
name: "小傅",
age: 20,
course: ["Go"]
}, (err, result1, result2) => { // 接收会多个对象参数
if (err) console.log("err", err);
else {
console.log("result1", result1);
console.log("result2", result2);
}
});
添加多个数据:
model.create([dataObj1, dataObj2], (err, resultArr) => {})
StudentModel.create([{ // 传入一个数组
name: "小郑",
age: 20,
course: ["MySQL"]
}, {
name: "小仲",
age: 22,
course: []
}], (err, result) => { // 接收回一个数组参数
if (err) console.log("err", err);
else console.log("result", result);
});
find
查询所有数据:
model.find((err, result) => {})
以数组的形式返回表中的数据;无数据则返回空数组
StudentModel.find((err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
根据条件查询:
模型.find(conditions, (err, result) => {})
模型.find({key: value}, (err, result) => {})
StudentModel.find({
age: 21
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
StudentModel.find({
name: /小傅/
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$gt
大于、$gte
大于等于、$lt
小于、$lte
小于等于、$ne
不等于StudentModel.find({
age: { $gte: 21 } // 年龄 >= 21 的
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$exists
:存在某属性StudentModel.find({
name: { $exists: false } // 没有设置 name 属性的
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
注意:如果是一个不存在的字段,比如 gender
,不论 $exists
为何值,都会返回所有的数据
StudentModel.find({
gender: { $exists: true }
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$size
:数组长度匹配StudentModel.find({
course: { $size: 2 }
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$in
、$nin
:在、不在指定的多个字段之内StudentModel.find({
name: { $in: ["小谢", "小胡"] } // 名字在 ["小谢", "小胡"] 里面的
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$all
:数组中是否存在指定的所有项StudentModel.find({
course: { $all: ["C++", "Java"] }
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$or
、$nor
:或者、或者取反StudentModel.find({
$or: [{ name: "小陈" }, { age: 22 }] // 名字为 [小陈] 或者 age 为 [22] 的
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$where
:可以使用 JS 代码 / 函数StudentModel.find({
$where: "this.age === 20"
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
返回指定字段:
model.find(conditions, projection, (err, result) => {})
{ name: 1 }
:只显示 name
属性 & _id
属性{ age: 1, _id: 0 }
:只显示 name
属性StudentModel.find(null, { name: 1, _id: 0 }, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
设置返回的数据格式:
模型.find(conditions, projection, options, (err, result) => {})
{ sort: { age: 1 } }
:按照 age 项,升序排列;-1
则降序排序{ skip: 2 }
:略过前 2 条数据{ limit: 5 }
:最多返回 5 条数据StudentModel.find(null, null, { sort: { age: 1 }, limit: 3 }, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
findOne
返回第一个查找到的数据,无数据则返回 null
StudentModel.findOne((err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
findbyId
根据 id 查询:model.findById(id, (err, result) => {})
返回指定数据,不存在该数据则返回 null
StudentModel.findById("6229fd57809fbf2dc34f83dd", (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
updateOne
更改一个数据:model.updateOne(condition, newData, callback)
StudentModel.updateOne({ name: "小仲" }, {
course: ["摸鱼"]
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
updateMany
更改多个数据:模型.updateMany(condition, newData, callback)
StudentModel.updateMany({ name: "小黄" }, {
$inc: { age: 1 } // age + 1
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
findByIdAndUpdate
根据 id 更改数据:模型.findByIdAndUpdate(id, newData, (err, oldData)=>{})
StudentModel.updateOne("622aea67f487ff334ba925d4", {
// 删除 age 字段,属性值随便写,反正都被删除了
$unset: { age: 0 }
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
更新数组元素
$push: { arr: XXX }
:为数组添加元素 XXXStudentModel.updateMany({ name: "小黄" }, {
$push: { course: "Vue" } // 为数组添加元素
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$addToSet: { arr: XXX }
:为数组添加元素 XXX,如果 XXX 已存在则不添加StudentModel.updateOne({ name: "小黄" }, {
$addToSet: { course: "React" } // 为数组添加元素,如果已存在则不添加
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$pop: { arr: 1 }
:删除数组的最后一项;如果设置为 -1
则删除第一项StudentModel.updateOne({ name: "小黄" }, {
$pop: { course: 1 } // 删除数组的最后一项;值为 -1 则删除第一项
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
$pull: { arr: XXX }
:删除数组所有值为 XXX 的元素StudentModel.updateOne({ name: "小黄" }, {
$pull: { course: "class" } // 删除数组的所有 class 值
}, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
remove
删除所有数据:
model.remove((err, result) => {})
StudentModel.remove((err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
根据条件删除:
model.remove({key, value}, (err, result) => {})
StudentModel.remove({ name: "小胡" }, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
findByIdAndRemove
根据 id 删除:model.findByIdAndRemove(id, (err, result) => {})
StudentModel.findByIdAndRemove("6229febe332cf70aa225c6b4", (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
deleteOne
删除一个数据:model.deleteOne(condition, (err, result) => {})
Student.deleteOne({ name: "小傅" }, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
deleteMany
删除多个数据:model.deleteMany(condition, (err, result) => {})
Student.deleteMany({ name: "小郑" }, (err, result) => {
if (err) console.log("err", err);
else console.log("result", result);
});
pre()
和 post()
方法init
、validate
、save
、remove
、count
、find
、findOne
、findOneAndRemove
、findOneAndUpdate
、insertMany
、update
、const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/demo').then(_ => {
console.log("连接成功!"); // 2
}, reason => {
console.log("连接失败!", reason);
});
// 创建 Schema 模式实例
const studentSchema = new mongoose.Schema({
name: String,
age: Number,
}, { versionKey: false });
// 设置钩子函数
studentSchema.pre('findOne', next => {
console.log("pre"); // 1
next();
});
studentSchema.post('findOne', res => {
console.log("post", "res", res); // 3
});
// 创建表模型
const StudentModel = mongoose.model('Student', studentSchema);
// 调用 findOne 方法
StudentModel.findOne((err, result) => {
if (err) console.log("err", err);
else console.log("result", result); // 4
});
mongoose.createConnection()
返回链接对象const mongoose = require('mongoose');
// 创建多连接
const con1 = mongoose.createConnection('mongodb://localhost:27017/demo');
const con2 = mongoose.createConnection('mongodb://localhost:27017/demo');
无论是使用 mongoose.connect
/ mongoose.createConnection
创建的连接
其连接池默认只能连接 5 个,可通过 poolSize
设置
mongoose.createConnection(url, {
poolSize: 4 // 设置连接池的连接数为 4
});
const mongoose = require("mongoose");
mongoose.connect('mongodb://localhost:27017/node').then(_ => {
console.log("连接成功!");
}, reason => {
console.log("连接失败!", reason);
});
const Schema = mongoose.Schema;
const studentSchema = new Schema({
name: String,
age: Number,
course: Array
});
const StudentModel = mongoose.model("Student", studentSchema);
const scoreSchema = new Schema({
pass: Boolean,
author: [{ // 关联 StudentModel
type: Schema.Types.ObjectId,
ref: StudentModel,
}]
})
const ScoreModel = mongoose.model("Score", scoreSchema);
// ScoreModel.create({
// pass: true,
// author: '622b321bbeaecc99728c70ee' // 这里填入某条记录的 _id
// }, (err, result) => {
// if (err) console.log("err", err);
// else console.log("result", result);
// })
ScoreModel.find().populate("author").exec((err, result) => {
if (err) console.log("err", err);
else {
console.log("result", result[0]);
console.log("author", result[0].author[0]);
}
});
<body>
<h1 id="bb">名字h1>
<button id="box">点击button>
body>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script>
box.onclick = () => {
axios({
method: "post",
url: "/register",
data: { name: 'superman' }
}).then(res => console.log("data", res.data));
};
// 免登录
(() => {
axios({ url: "/getSession" }).then(res => {
console.log("data", res.data);
bb.innerText = res.data.value
})
})();
script>
const express = require("express");
const app = express();
app.listen(8080, () => console.log("http://127.0.0.1:8080"));
app.use(express.static("./public"));
// 解析 post 的数据
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 使用 mongoose
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/node")
.then(() => console.log("连接成功!"))
.catch(() => console.log("连接失败!"));
let userSchame = new mongoose.Schema({
name: String,
pass: String,
});
let UserModel = mongoose.model("User", userSchame);
// 将 session 放入数据库
const session = require("express-session"); // 用于操作 session
const MongoStore = require("connect-mongo"); // 用于存储 session 到 MongoDB
app.use(session({
secret: 'keyboard cat', // 加密的字符串,里面内容可以随便写
resave: false, // 强制保存 session,即使它没变化
saveUninitialized: true, // 强制将未初始化的 session 存储,默认为 true
cookie: { // 配置 cookie
maxAge: 1000 * 60 * 60 * 24, // 有效期为 1 天
secure: false, // 是否仅 https 可用
},
store: MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/node' }) // 存入 MongoDB
}));
// 配置 session
app.post("/register", (req, res) => {
req.session.user = req.body; // 添加 session 属性
console.log("session", req.session); // 获取 session
res.send("设置 session")
})
// 免登录
app.get("/getSession", async (req, res) => {
console.log("name", req.session.name);
if (req.session.user) {
// 在 MongoDB 中查询、获取用户数据
let result = await UserModel.findOne({ name: "superman" });
res.send({
code: 1,
value: req.session.user.name, // 获取 session 属性
result
});
} else {
res.send({ code: 0, value: "过期了" });
}
});