一、基础知识
1.1、什么是MongoDB
MongoDB 是由C++语言编写的,是一个基于【分布式】文件存储的【开源】数据库系统(NoSQL)
特点
- 海量存储:方便扩展,多节点部署,形成集群
- 文档数据库:数据结构由键值(key=>value)对组成
- 支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言
- 可以直接允许JavaScript脚本
1.2、组成
1.3、文档
官方定义
- 文档是一个键值(key-value)对
- 以二进制的JSON存储(BSON)
示例
{
"usernaem";"李明",
"age":21,
"sex":"男",
"email":"liming@example.com",
"address":"南大街43号",
"company":{
"name": "科技公司",
"industry":"互联网"
}
}
键的命名要求
- 不能含有\0(空字符)
- 避免.$_x(下划线开头)
文档的特点
- 键值(key-value)对是有序的
- 键(key)唯一,不可重复
- 键区分类型和大小写
- 文档可以嵌套
数据类型
ObjectId
- 特点及用途:小,几乎唯一,可快速生成,方便排序(常用于文档的主键)
- 生成规则:系统当前时间(秒) + 随机数 + 自增值
- 常用方法:getTimestamp():获取时间、str:获取ObjectId的字符串
1.4、集合
- 官方定义:集合就是MongoDB中的文档组
- 理解集合:【集合】类似于关系数据中的表
- 对比关系型数据库:集合中的文档【没有】固定的结构
命名规则
- 不能包含\0字符(空字符"")
- 不能使用system.的前缀(系统保留)
- 建议不包含保留字 “$”
- 用 . 分割不同命名空间的子集合(如:blog.users,blog.posts)
1.5、数据库
- 多个文档组成集合,多个集合组成数据库
- 一个实例可以承载多个数据库(逻辑库)
- 每个数据库都有独立的权限
- 保留的数据库名称(admin,local,config)
1.6、MongoDB与MySQL术语比较
二、MongoDB安装及配置
2.1、安装
- 第一步,下载MongoDB社区版
https://www.mongodb.com/try/download/community - 第二步,安装
2.2、启动
系统服务启动
命令行启动(需要以管理员身份运行)
net start/stop MongoDB
三、数据库管理
3.1、Mongo Shell
MongoDB自带的命令行管理工具
- 第一步,进入MongoDB安装目录/bin
- 第二步,打开命令行窗口,输入
mongo --host 127.0.0.1 --port 27017
,如果是默认安装可以直接输入mongo
可以直接把MongoDB安装目录/bin,加入到环境变量Path中,就可以随时通过命令行,输入mongo
就可以连接。
3.2、图形化管理工具
- Navicat
- Robo 3T(免费)
- Studio 3T(收费)
3.3、数据库管理
- 查看所有数据库:
show dbs
- 创建/切换数据库:
use db_name
- 获取当前正在操作的数据库:
db
- 删除数据库:
db.dropDatabase()
3.4、集合管理
- 查看所有集合:
show collections
- 创建集合(当插入数据时会自动创建):
db.createCollection("students")
- 删除集合:
db.COLLECTION_NAME.drop()
,COLLECTION_NAME,实际集合的名称 - 重命名集合:
db.COLLECTION_NAME.renameCollection("temp")
- 为集合中的某些域(列)创建索引:
db.COLLECTION_NAME.createIndex(keys, <options>, <commitQuorum>)
四、数据管理
4.1、插入数据
插入单条数据
语法参考:db.COLLECTION_NAME.insertOne(document)
返回结果:{ "acknowledged" : true, "insertedId" : ObjectId("60fe0c40fe9b36874a43644f") }
插入多条数据
语法参考:db.COLLECTION_NAME.insertMany([doc1, doc2])
返回结果:{ "acknowledged" : true, "insertedId" : [ObjectId("..."), ObjectId("...")] }
4.2、查询数据
4.2.1、查询一条/多条数据
查询一条数据
语法参考:db.COLLECTION_NAME.findOne(<filter>, <projection>)
参数解释
- filter:查询条件(可选参数)
- projection:需要返回的域(字段)(可选参数)
示例
//查询第一条数据
db.students.findOne();
//指定显示的列
db.students.findOne({},{"stu_no":1, "stu_name":1, "address":1});
//指定显示的列,指定_id不显示
db.students.findOne({},{"stu_no":1, "stu_name":1, "address":1, "_id":0});
查询所有数据
语法参考:db.COLLECTION_NAME.find({})
格式化显示(带缩进):db.COLLECTION_NAME.find().pretty()
4.2.2、条件查询
查询条件
-
比较运算符
示例代码// 查询年龄大于12岁的所有学生 db.students.find({"age": {$gt: 12}}); // 查询年龄在9~12之间(含)的学生信息 db.students.find({"age": {$gte: 9, $lte: 12}}); // 查询未设置/已设置年龄的学生信息 db.students.find({"age": null}); db.students.find({"age": {$ne: null}}); // 查询学生年龄在9岁和12岁的学生信息 db.students.find({"age": {$in: [9, 12]}});
-
逻辑运算符
// 查询所有12岁以上的男生和9岁以下的女生 db.students.find({ $or:[ {"sex": "男", "age": {"$gt": 12}}, {"sex": "女", "age": {"$lt": 9}} ] });
-
支持JavaScript正则表达式
// 查找所有姓“李”的学生信息 db.students.find({stu_name: /^李/}); // 查找所有姓“李”, 名只有一个字的学生信息 db.students.find({stu_name: /^李.$/}); // 查找姓名中包含“雪”字的学生信息 db.students.find({stu_name: /雪/});
-
嵌套文档查询,使用点号(.)分割key
示例代码:db.COLLECTION_NAME.find({"a.b": "c"})
// 查询所有学生的语文成绩 db.grades.find({"grade.course_name": "语文"}); // 查找所有学生中语文成绩已经及格的学生信息 db.grades.find({"grade.course_name": "语文", "grade.score": {$gte: 60}}); db.grades.find({$and: [ {"grade.course_name": "语文"}, {"grade.score": {$gte: 60}} ]});
-
在数组内查询
// 查询只有两门成绩的学生信息 db.students.find({grades: {$size: 2}});
4.2.3、聚合统计
-
查看集合中文档的数量,可以链式调用
db.COLLECTION_NAME.count()
-
去掉重复的内容
db.COLLECTION_NAME.distinct(field_name, <filter>)
示例
// 查询只有两门成绩的学生信息
db.students.find({grades: {$size: 2}});
// 统计学生总数
db.students.count();
// 查询只有两门成绩的学生信息总人数
db.students.find({grades: {$size: 2}}).count();
// 查找“三年级一班”学生的居住区域
db.students.distinct("address", {"class_name": "三年级一班"});
语法参考
db.COLLECTION_NAME.aggregate([
// where
{$match: {"grade.score":{$gte: 60}}},
// group by
{$group: {_id : "$stu_no", total: {$sum: 1}}},
// having
{$match: {total: {$eq: 3}}}
])
内置聚合统计函数
// 统计语文成绩的最高分/最低分/平均分
db.grades.aggregate([
// where
{$match: {"grade.course_name": "语文"}},
// group by
{$group: {
_id: null,
maxSource: {$max: "$grade.score"},
minSource: {$min: "$grade.score"},
avgSource: {$avg: "$grade.score"},
}},
]);
// 统计张三各科总分
db.grades.aggregate([
// where
{$match: {"stu_name": "张三"}},
// group by
{$group: {
_id: null,
maxSource: {$sum: "$grade.score"},
}},
]);
// 统计每个班的学生人数
db.students.aggregate([
// group by
{$group: {
_id: "$class_name",
total: {$sum: 1},
}},
]);
// 统计每个班男生、女生总人数
db.students.aggregate([
// group by
{$group: {
_id: {class_name: "$class_name", sex: "$sex"},
total: {$sum: 1},
}},
]);
// 查找三门成绩都及格(>=60)的学生
db.grades.aggregate([
// where
{$match: {"grade.score": {$gte: 60}}},
// group by
{$group: {
_id: "$stu_no",
total: {$sum: 1},
}},
// having
{$match: {total: {$eq: 3}}}
]);
4.3.4、排序和分页
排序
语法参考:db.COLLECTION_NAME.find().sort({field: value})
排序规则
- 1:升序
- -1:降序
示例
// 将学生的语文成绩从高到低排序
db.grades.find({"grade.course_name": "语文"}).sort({"grade.score": -1});
// 将学生的语文成绩按照年龄和成绩排序
db.grades.find({"grade.course_name": "语文"}).sort({"grade.score": -1, "age": -1});
分页
语法参考:db.COLLECTION_NAME.find().skip(10).limit(10)
方法解释
- skip(N):跳过N行数据
- limit(N):取N行数据
// 获取第三页学生成绩信息,每页8条
db.grades.find().skip(16).limit(8);
4.3、更新数据
以下三种方法使用上类似,以updateMany方法为例
- updateOne():更新一条数据
- replaceOne():替换一条数据
- updateMany():更新多条数据
语法参考:db.COLLECTION_NAME.updateMany(<filter>, <update>, <options>)
参数解释
- 第一个参数:<filter>,查询条件,修改满足条件的数据
- 第二个参数:<update>,需要修改的数据对象
更新数据表达式
示例
// 创建users集合,并插入文档数据
db.users.insertMany([{"username": "cjw", "age": 12},{"username": "cjw01", "age": 13},{"username": "cjw02", "age": 14},{"username": "cjw03", "age": 15}]);
db.users.insertMany([{"username": "cjw04", "age": 16, "hobby": ["篮球", "足球"], "company": {"address": "明珠街"}}]);
// 设置用户的年龄为20岁
db.users.updateMany({}, {$set: {"age": 20}});
// 删除用户的爱好和公司信息
db.users.updateMany({}, {$unset: {"company": null, "hobby": null}});
// 添加用户created_at为系统当前时间
db.users.updateMany({}, {$currentDate: {"created_at": true}});
// 将用户的年龄+1
db.users.updateMany({}, {$inc: {"age": 1}});
4.4、删除数据
删除单条数据
语法参考:db.COLLECTION_NAME.deleteOne(<filter>)
批量删除数据
语法参考:db.COLLECTION_NAME.deleteMany(<filter>)
删除集合中所有的数据:db.COLLECTION_NAME.deleteMayn({})
练习
//查询年龄在9~12之间(含)的学生信息(学号,姓名,年龄和班级)
db.students.find({"age": {$gte: 9, $lte: 12}},{"stu_no":1, "stu_name":1, "age":1, "class_name":1});