赞
踩
MongoDB 是一个基于分布式文件存储的数据库(官方地址)
数据库(DataBase)是按照数据结构来组织、存储和管理数据的应用程序
数据库的主要作用就是 管理数据,对数据进行 增(c)、删(d)、改(u)、查(r)
相比于纯文件管理数据,数据库管理数据有如下特点:
操作语法与 JavaScript 类似,容易上手,学习成本低
MongoDB 中有三个重要概念需要掌握:
JSON 文件示例:(用于理解上面的概念)
{ // 一个 json 文件就代表一个数据库 "accounts": [ // 代表一个集合(即数据表) { // 每一个对象就是一个文档(即数据表中的字段) "id": "7JivnCf3M", "title": "买复习材料", "time": "2024-03-25", "type": "-1", "account": "89", "remarks": "买书了,就一定要去看啊!" }, { "id": "4ZqPLTsJB", "title": "发工资", "time": "2024-03-23", "type": "1", "account": "90000", "remarks": "终于发工资了!" }, { "id": "l3nKzkhw7", "title": "报班", "time": "2024-03-14", "type": "-1", "account": "10000", "remarks": "迫不得已,不得不去" }, { "id": "BaA0bRfh8", "title": "买水果", "time": "2024-03-01", "type": "-1", "account": "20", "remarks": "好久没吃水果了,今天吃一吃" } ], "users": [ // 代表一个集合(即数据表) { // 每一个对象就是一个文档(即数据表中的字段) "id": 1, "name": "zhangsan", "age": 18 }, { "id": 2, "name": "lisi", "age": 20 }, { "id": 3, "name": "wangwu", "age": 22 } ] }
我们可以通过 JSON 文件来理解 MongoDB 中的概念:
一般情况下:
- 一个项目使用一个数据库
- 一个集合会存储同一类型的数据
下载地址:MongoDB 官网
建议选择 zip
类型,通用性更强。因为选择下载的是 .zip 文件,所以直接解压,一步到位
解压后文件里面的目录结构如下:
选择任一磁盘创建空文件夹(不要使用中文路径),将解压之后的文件夹内容剪切进去(我选择的是D盘)
手动创建 data 和 log 两个文件夹:
配置环境变量(打开“开始”搜索“环境变量”即可)
找到 Path,进行编辑,将自己的 MongoDB 的 bin 文件地址添加上去
创建 db 文件夹(在 data 目录下,创建 db 文件夹)
因为启动 MongoDB 服务之前必需创建数据量文件的存放文件夹,否则命令不会自动创建,而且不能确定成功。
在 bin 目录上直接输入 cmd
输入命令
输入如下命令后按回车,后面的路径是 data 文件夹下的 db 目录路径(类似 D:\MongoDB\data\db)
mongod --dbpath D:\MongoDB\data\db
回车后会看到一大堆下面这样的(找到 waiting for connections,则表明服务 已经启动成功)
成功
在浏览器中输入下面的地址:
http://localhost:27017/
若显示结果如下,就说明安装成功并结束,也代表服务已经启动成功
使用 mongo
连接本地的 MongoDB 服务
注意:
- 为了方便后续使用 mongod 或 mongo 命令,可以将 bin 目录配置到环境变量 Path 中
- 千万不要选中服务端窗口的内容,选中后会停止服务,可以通过 敲回车 取消选中来解决
命令行交互一般是学习数据库的第一步,不过这些命令在后续用的比较少,所以我们只需要了解即可
显示所有的数据库
show dbs
切换到指定的数据库,如果数据库不存在会自动创建数据库
use 数据库名
显示当前所在的数据库
db
删除当前数据库
use 库名
db.dropDatabase()
创建集合
db.createCollection('集合名称')
显示当前数据库中的所有集合
show collections
删除某个集合
db.集合名.drop()
重命名集合
db.集合名.renameCollection('newName')
插入文档
db.集合名.insert(文档对象)
查询文档
db.集合名.find(查询条件)
// 不加查询条件的话,得到的是所有的文档
_id 是 MongoDB 自动生成的唯一编号,用来唯一标识文档
更新文档
// 这个方法相当于重写,即用“新的文档”覆盖掉“旧的文档”来实现更新文档的功能,从而导致文档中不需要更新的内容发生丢失
db.集合名.update(查询条件, 新的文档)
// 例如:更新 name 为‘张三’的 age = 35 --> 最终得到的结果虽然更新了age,但是其name属性丢失了
dp.users.update({name: '张三'}, {age: 35})
// 这个方法可以实现更新文档中的某一个数据,并且不会发生数据丢失的情况
db.集合名.update(查询条件, {$set:要更新的文档})
// 例如:
db.集合名.update({name: '张三'}, {$set:{age: 19}})
删除文档
db.集合名.remove(查询条件)
方便使用代码去操作 MongoDB 数据库
优势:
npm i mongoose
const mongoose = require('mongoose')
mongoose.connect('mongodb://数据库ip地址:端口号(默认端口27017可以省略)/数据库名')
使用 mongoose 完成对 MongoDB 数据库的连接
代码示例:
// 1.安装 mongoose ==> npm i mongoose // 2.导入 mongoose const mongoose = require('mongoose') // 3.连接 mongodb 服务(mongodb 服务的默认端口是27017,所以可写可不写) // mongodb://127.0.0.1:27017/bilibili 分别是:协议名称 IP地址 端口号 数据库名称 mongoose.connect('mongodb://127.0.0.1:27017/bilibili') // 4.设置回调 // 设置连接成功的回调 mongoose.connection.on('open', () => { console.log('连接成功') }) // 设置连接错误的回调 mongoose.connection.on('error', () => { console.log('连接失败') }) // 设置连接关闭的回调 mongoose.connection.on('close', () => { console.log('连接关闭') }) // 关闭 mongodb 的连接 setTimeout(() => { mongoose.disconnect() }, 2000)
在实现使用 mongoose 对 MongoDB 数据库连接的基础上,完成如下的操作:
创建文档的结构对象(Schema)
let BookSchema = new mongoose.Schema({ // 设置集合中文档的属性以及属性值的类型 例如: name: String, price: Number // ..... })
- 1
- 2
- 3
- 4
- 5
- 6
- 通过
Schema
创建Model
- Model 代表的是数据库中的集合,通过 Model 才能对数据库进行操作
创建模型对象(Model)
let BookModel = mongoose.model('books', BookSchema)
- 1
参数:
- 要映射的集合名称
- 创建的约束(Schema 对象)
通过 Model 返回的值对数据进行增、删、改、查(这里实现的是增)
BookModel.create({ name: '西游记', author: '吴承恩', price: 19.9 }).then((data) => { console.log(data) // 插入成功 }).catch((err) => { console.log(err) // 插入失败 })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
注意:高版本的 mongoose 的 create 方法是没有第二个参数(即回调函数),而是返回了一个 Promise 对象,所以我们需要采用 then 和 catch 方法来捕获状态。
断开数据库连接(程序运行过程中,一般不会使用)
mongoose.disconnect()
- 1
代码示例:
// 1.安装 mongoose // 2.导入 mongoose const mongoose = require('mongoose') // 3.连接 mongodb 服务 mongoose.connect('mongodb://127.0.0.1:27017/bilibili') // 4.设置回调 // 设置连接成功的回调 mongoose.connection.once('open', () => { // console.log('连接成功') // 5.创建文档的结构对象(Schema:模式,可以理解为结构) // 设置集合中文档的属性以及属性值的类型 let BookSchema = new mongoose.Schema({ name: String, author: String, price: Number }) // 6.创建模型对象(模型对象是对文档操作的封装对象) // 参数1:集合名称 参数2:结构对象 let BookModel = mongoose.model('books', BookSchema) // 7.新增 /** * 报错问题:MongooseError: Model.create() no longer accepts a callback * 原因:在旧版本中 Model.create() 的第二个参数是一个回调函数,用来捕获成功或异常;但是在最新 * 版本中,Model.create() 中没有第二个参数了,而是返回了一个 Promise 对象,我们将采用 * then 方法和 catch 方法来捕获状态 * * then:捕获成功 * catch:捕获失败 */ BookModel.create({ name: '西游记', author: '吴承恩', price: 19.9 }).then((data) => { console.log(data) // 增加成功 // 8.关闭数据库连接(项目运行过程中,不会添加该代码) mongoose.disconnect() }).catch((err) => { console.log(err) // 增加失败 }) }) // 设置连接错误的回调 mongoose.connection.on('error', () => { console.log('连接失败') }) // 设置连接关闭的回调 mongoose.connection.on('close', () => { console.log('连接关闭') })
文档结构可选的常用字段类型列表:
类型 | 描述 |
---|---|
String | 字符串 |
Number | 数字 |
Boolean | 布尔值 |
Array | 数组,也可以使用 [] 来标识 |
Date | 日期 |
Buffer | Buffer 对象 |
Mixed | 任意类型,需要使用 mongoose.Schema.Types.Mixed 指定 |
ObjectId | 对象 ID,需要使用 mongoose.Schema.Types.ObjectId 指定 |
Decimal128 | 高精度数字,需要使用 mongoose.Schema.Types.Decimal128 指定 |
代码示例:
// 导入 mongoose const mongoose = require('mongoose') // 连接 mongodb 服务 mongoose.connect('mongodb://127.0.0.1:27017/mongoose_test') // 设置回调 // 设置连接成功的回调 mongoose.connection.once('open', () => { // 创建文档的结构对象 let BookSchema = new mongoose.Schema({ name: String, author: String, price: Number, is_hot: Boolean, // 关于数组类型的标识:除了使用 Array 外,还可以使用 [] 来标识 tags: [], pub_time: Date, test: mongoose.Schema.Types.Mixed }) // 创建模型对象 let BookModel = mongoose.model('books', BookSchema) // 新增 BookModel.create({ name: '西游记', author: '吴承恩', price: 19.9, // 属性名被写错时,那么该属性名就会被忽略 is_hot: true, // 如果写的"true"或"false",会自动转换为布尔值 tags: ['鬼怪', '神话', '励志'], pub_time: new Date(), test: 99 }).then((data) => { console.log(data) // 增加成功 // 关闭数据库连接 mongoose.disconnect() }).catch((err) => { console.log(err) // 增加失败 }) }) // 设置连接失败的回调 mongoose.connection.on('err', () => { console.log('连接失败') }) // 设置连接关闭的回调 mongoose.connection.on('close', () => { console.log('连接关闭') })
Mongoose 有一些内建验证器,可以对字段值进行验证
// 给 name 属性设置必填项,就必须给 name 赋值,否则会报错(name: Path `name` is required)
name: {
type: String,
required: true // 设置必填项
}
// 给 author 属性设置默认值
author: {
type: String,
default: '匿名' // 设置默认值(未设置属性值时,会使用该默认值)
}
// 给 style 属性设置枚举值
style: {
type: String,
enum: ['神话', '小说', '鬼怪'] // 设置的属性值都必须是该数组中的,否则会报错(style: `a` is not a valid enum value for path `style`)
}
// 给 username 设置唯一值,那么该属性的属性值是独一无二的,否则会发生报错
username: {
type: String,
unique: true // 注:unique 需要重新创建集合才能有效果
}
unique 需要 重建集合 才能有效果
开发定理:永远不要相信用户的输入
数据库的基本操作包括四个:增加(create)、删除(delete)、修改(update)、查询(read)
增加一条数据:(create)
BookModel.create({
name: '西游记',
author: '吴承恩',
price: 19.9,
is_hot: true
}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
增加多条数据:(insertMany)
BookModel.insertMany([ { name: '与病毒同行', author: '沐日海洋', price: 9.9, is_hot: true }, { name: '末日技能树', author: '暗黑茄子', price: 9.9, is_hot: true } ]).then((data) => { console.log(data) }).catch((err) => { console.log(err) })
删除一条数据:(deleteOne)
BookModel.deleteOne({_id: '65f7af461fe13910a107685f'}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
删除多条数据:(deleteMany)
BookModel.deleteMany({is_hot: false}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
修改一条数据:(updateOne)
BookModel.updateOne({name: '红楼梦'}, {price: 9.9}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
修改多条数据:(updateMany)
BookModel.updateMany({author: '余华'}, {is_hot: false}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
查询一条数据:
findOne:
BookModel.findOne({author: '沐日海洋'}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
findById:
// 还可以使用 findById(根据 id 查询数据)
BookModel.findById('65f7cf5bef9a5f1f2084bc90').then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
查询多条数据:(find)
不加条件查询(查询所有)
BookModel.find().then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
加条件查询
BookModel.find({price: 9.9}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
在 mongodb 中不能使用 > < >= <= !== 等运算符,需要使用替代符号:
>
使用 $gt
<
使用 $lt
>=
使用 $gte
<=
使用 $lte
!==
使用 $ne
BookModel.find({price: {$lt: 10}}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
$or
逻辑或的情况
BookModel.find({$or: [{author: '余华'}, {author: '沐日海洋'}]}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
$and
逻辑与的情况
BookModel.find({$and: [{price: {$gt: 30}}, {price: {$lt: 70}}]}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
条件中可以直接使用 JS 的正则语法,通过正则可以进行模糊查询:
// 语法格式为:(key 表示实现模糊查询的关键字)
// 比如:搜索书籍名称中带有‘三’的图书,那么 key 就为‘三’
BookModel.find({属性名: /key/})
BookModel.find({name: /三/}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
另一种写法:
BookModel.find({name: new RegExp('三')}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
有些时候关键字究竟是什么,你不确定,它可能放在一个变量当中,而如果是变量的话,将其放在‘/key/’上是无法解析,那么就需要使用 new RegExp(‘key’) 这种方式了
// 通过 select 可以设置字段,来实现字段筛选 —— 格式:select({属性名: 1}) / select({属性名: 0})
// 0:不要的字段
// 1:要的字段
BookModel.find().select({name: 1, author: 1, _id: 0}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
// 通过 sort 可以实现数据排序 —— 格式:sort({属性名: 1}) / sort({属性名: -1})
// 1:升序
// -1:降序
BookModel.find().select({name: 1, price: 1, _id: 0}).sort({price: -1}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
// 通过 skip 可以实现跳过数据 —— 格式:skip(n) --- 跳过 n 条数据
// 通过 limit 可以实现限定获取数据 —— 格式:limit(n) --- 限定获取 n 条数据
// 通常情况下,我们会将 skip 和 limit 一起使用,用来实现分页器
BookModel.find().select({name: 1, price: 1, _id: 0}).sort({price: -1}).skip(3).limit(3).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
经过前面的学习,我们会发现有很多代码是一直在重复的书写,这在实际开发中,是很浪费时间的,所以我们需要对 mongoose 模块化,将一些重复的代码提取出来并将其封装起来:
创建配置文件夹,再创建配置文件 config.js,然后将IP地址、端口号以及数据库名称写入该文件中:(以后便于修改)
// 配置文件
module.exports = {
DBHOST: '127.0.0.1',
DBPORT: 27017,
DBNAME: 'mongoose_test'
}
创建 db 文件夹,再创建 db.js 文件,然后将以下代码写入 db.js 文件中:(导入配置文件,获取连接数据库的参数)
/** * * @param {*} success 数据库连接成功的回调 * @param {*} error 数据库连接失败的回调 */ module.exports = function (success, error) { // 判断 error 为其设置默认值 if(typeof error !== 'function') { error = () => { console.log('连接失败~~~') } } // 导入 mongoose const mongoose = require('mongoose') // 导入配置文件(解构赋值) const {DBHOST, DBPORT, DBNAME} = require('../config/config') // 连接 mongodb 服务 mongoose.connect(`mongodb://${DBHOST}:${DBPORT}/${DBNAME}`) // 设置连接成功的回调 mongoose.connection.once('open', () => { success() }) // 设置连接错误的回调 mongoose.connection.on('error', () => { error() }) // 设置连接关闭的回调 mongoose.connection.on('close', () => { console.log('连接关闭') }) }
创建 model 文件夹,然后创建不同集合的 Model.js 文件,并写入创建结构对象和创建模型对象的代码:
比如:创建集合 novel 的 BookModel.js 文件
// 导入 mongoose
const mongoose = require('mongoose')
// 创建文档的结构对象(Schema:模式,可以理解为结构)
let BookSchema = new mongoose.Schema({
name: String,
author: String,
price: Number
})
// 创建模型对象(模型对象是对文档操作的封装对象)
let BookModel = mongoose.model('novel', BookSchema)
// 暴露 BookModel
module.exports = BookModel
最后,创建 index.js 并导入 db.js 和 Model.js,将对数据库的增删改查都在 index.js 中操作:
// 导入 db 文件 const db = require('./db/db') // 导入 mongoose const mongoose = require('mongoose') // 导入 BookModel const BookModel = require('./model/BookModel') // 调用 db 函数 db(() => { // 查询 BookModel.findOne({ author: '沐日海洋' }).then((data) => { console.log(data) // 关闭数据库连接 mongoose.disconnect() }).catch((err) => { console.log(err) }) })
我们可以使用图形化的管理工具来对 Mongodb 进行交互,这里演示两个图形化工具:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。