# MongoDB
MongoDB是nosql数据库。没有行和列的概念,用JSON键值对来存储数据。
集合就相当于“表”,文档就相当于“行”
# 一、基本使用
mongo
:连接数据库
show dbs
:查看当前数据计算机中的数据库
use DB_name
:使用切换到数据库、创建数据库(use 之后才能使用db对象进行操作)
db
:查看当前所在的数据库
show collections
:查看数据库中的表(集合)
# 1】插入数据
db.user.insert({"username":"zhangsan","age":20})
:创建user表(集合)以及插入数据
db.user.drop()
:删除user表(集合)
db.dropDatabase()
:删除数据库,首先需要use DB_name切换到数据库,才能删除数据库
# 2】查找数据
db.user.find()
:查找数据库中的user表(集合)中的所有记录
db.user.find({"age":20})
:查找user表(集合)中age=20的记录
db.user.find({"age":{$gt:22}})
:查找user表(集合)中age>22的记录
db.user.find({"age":{$gte:22}})
:查找user表(集合)中age>=22的记录
db.user.find({"age":{$lt:22}})
:查找user表(集合)中age<22的记录
db.user.find({"age":{$lte:22}})
:查找user表(集合)中age<=22的记录
db.user.find({"age":{$gte:20,$lte:30}})
:查找user表(集合)中20<=age<=30的记录
db.user.find({"username":/zhang/})
:模糊查找user表(集合)中的记录(正则表达式一致)
db.user.find({},{name:1})
:指定列查询数据(第二个参数)只显示name列的记录
db.user.find().sort({age:-1})
:排序,1表示升序,-1表示降序
db.user.find().limit(5)
:查询前5条数据
db.user.find().skip(10)
:查询10条以后的数据
db.user.find().skip(2).limit(2)
:查询第3-4条数据(可用于列表分页)
db.user.find().count()
:查询表中的记录数量(统计数据total)
还可以使用for循环进行造数据:
for(var i=0;i<100;i++){
db.admin.insert({"username":"wang"+i,"age":i})
}
db.admin.find()//自动进行分页展示,每页20条数据
db.admin.find().count()//100
db.user.find().skip(10).limit(10)//自定义分页展示,pageSize=10,第二页的数据
db.user.find({$or:[{age:22},{age:25}]})
:查询age=22或者age=25的记录
db.user.findOne()
:只查询第一条记录
find查出来是一个数组,findOne查出来是一个对象
# 3】修改数据
前面是查询条件,后面是更新操作($set更新所有匹配的项目),最后是是否开启更新多条记录
db.user.update({"name":"小明"},{$set:{"age":33}},{multi:true})
:查找name="小明"的记录,把age改成33并且修改多条查询到的数据
db.user.update({"name":"小明"},{"age":16})
:查找name="小明"的记录,全部替换成{"age":16}
# 4】删除数据
db.user.remove({age:132})
:删除age=132的数据
db.user.remove({})
:删除所有数据
db.user.remove({},{justOne:true})
:只删除查找到的第一条数据
# 二、索引基础
设置索引可以优化查询速度,但是插入的速度会变慢。
db.user.find({"username":zhangsan24231}).explain("executionStatus")
:查看代码执行信息
# 1】创建索引
db.user.ensureIndex({"username":1})
:给user表中的username字段创建一个索引
db.user.ensureIndex({"username":1},{"name":"userindex"})
:可以传入第二个参数,给当前设置的索引起别名
# 2】查看表中的索引
db.user.getIndexes()
:获取user表中的所有索引
# 3】删除索引
db.user.dropIndex({"username":1})
:删除user表中的username字段的一个索引
# 4】复合索引
db.user.ensureIndex({"username":1,"age":-1})
:数字1表示username键的索引按升序存储,-1表示age键的索引按降序存储。
db.user.find({"username":"zhangsan","age":30})
:会命中当前复合索引db.user.find({"username":"zhangsan"})
:会命中当前复合索引db.user.find({"age":30,"username":"zhangsan"})
:不会会命中当前复合索引(如果查询条件中的键值顺序和复合索引中创建顺序不一致,MongoDB会帮我智能调整顺序)db.user.find({"age":30})
:不会命中当前复合索引(如果想用到复合索引,必须在查询条件中包含复合索引中的前N个索引列)
# 5】唯一索引
db.user.ensureIndex({"age":1},{"unique":true})
:为age键创建唯一索引(age值不能重复)
# 三、权限配置
# 1】创建超级管理员账户(root)
use admin
db.createUser({
user:'admin',
pwd:'123456',
roles:[{role:'root',db:'admin'}]
})
# 2】修改数据库配置文件
修改配置文件,启用权限配置(不管修改什么配置文件都需要备份一下该文件)
//路径:mongoDB\Server\4.0\bin\mongod.cfg
//配置:
security:
authorization:enabled
# 3】重启mongodb服务
# 4】使用超级管理员账户连接数据库
mongo admin -u 用户名 -p 密码
mongo 192.168.1.200:27017/test -u user -p password
# 5】给eggcms数据库创建一个用户,只能访问eggcms不能访问其他数据库(dbOwner对当前数据库有所有的权限)
use eggcms
db.craeteUser({
user:'eggadmin',
pwd:'123456',
roles:[{role:'dbOwner',db:'eggcms'}]
})
# 6】命令
show users
:查看当前数据库下的用户db.dropUser('eggadmin')
:删除用户db.updateUser('admin',{pwd:'password'})
:修改用户密码db.auth('admin','password')
:密码认证
# 四、表与表之间关系
- 一对一
- 例如:一个人对应一个唯一身份证号,即为一对一的关系
- 一对多
- 例如:一个班级对应多名学生,即为一对多的关系
- 多对多
- 例如:一个学生可以选多门课程,而同一课程可以被多个学生选修,彼此的对应关系,即是多对多的关系
# 五、聚合管道
aggregation pipeline:使用聚合管道可以对集合中的文档进行变换和组合。(作用:表的关联查询、数据的统计)
MongoDB中使用db.COLLECTION_NAME.aggregate([{<stage>},...])
方法来构建和使用聚合管道。先看下官网给的实例,感受一下聚合管道的用法:
# 1】管道操作符:
$project
:增加、删除、重命名字段(对列进行筛选)
$match
:条件匹配。只满足条件的文档才能进入下一阶段
$limit
:限制结果的数量
$skip
:跳过文档的数量
$sort
:条件排序
$group
:条件组合、统计结果
$lookup
:用以引入其它集合的数据(表之间关联查询)
# 2】sql和nosql对比:
SQL | NOSQL |
---|---|
WHERE | $match |
GROUP BY | $group |
HAVING | $match |
SELECT | $project |
ORDER BY | $sort |
LIMIT | $limit |
SUM() | $sum |
COUNT() | $sum |
JOIN | $lookup |
# 3】$project
db.order.aggregate([
{
$project:{order_id:1, trade_no:1, all_price:1}
//只显示order_id、trade_no和all_price字段
}
])
# 4】$match
db.order.aggregate([
{
$project:{order_id:1, trade_no:1, all_price:1}
//管道1:筛选需要的字段
},
{
$match:{all_price:{$gte:90}}
//(all_price>=90)管道2:查询条件
}
])
# 5】$group
db.order.aggregate([
{
$group:{id:"$order_id", total:{$sum:"$num"}}
//以order_id进行分组,再将相同的id的num字段进行求和
}
])
# 6】$sort
db.order.aggregate([
{
$sort:{all_price:-1}
//将数据以all_price字段进行排序:-1表示降序,1表示升序
}
])
# 7】$limit
db.order.aggregate([
{
$limit:1
//限制输出的数据条数(结合$skip进行分页查询操作)
}
])
# 8】$skip
db.order.aggregate([
{
$skip:1
//跳过第一条数据,进行数据展示
}
])
# 9】$lookup
表关联:
db.order.aggregate([//在order表中进行管道操作(主表)
{
$lookup:{//关联表查询
from:"order_item",//需要关联的表是:order_item(非主表)
localField:"order_id",//order表(主表)中需要关联的字段
foreignField:"order_id",//order_item(非主表)中需要关联的字段
as:"items"//关联查询后把order_item(非主表)对应结果放到order表(主表)的items字段中
}
}
])
//[{order_id:1, trade_no:007, items:[{order_id:1,title:'书包'},{order_id:1,title:'笔记本'}]},{order_id:2, trade_no:007, items:[{order_id:2,title:'笔'}]}]
# 六、备份与还原
#备份
mongodump -h dbhost -d dbname -o dbdirectory
mongodump -h 127.0.0.1 -d orders -o D:\backup\db
-h:mongoDB所在服务器地址,例如:127.0.0.1当然也可以指定端口号127.0.0.1:27017
-d:需要备份的数据库实例,例如:test
-o:备份的数据存放位置,例如:/home/mongodump/,当然该目录需要提前建立,这个目录里面存放数据库实例的备份数据。
#还原
mongorestore -h dbhost -d dbname dbdirectory
mongorestore -h 127.0.0.1 -d orders D:\backup\db
-h:mongoDB所在服务器地址
-d:需要备份的数据库实例,例如:test,当然这个名称也可以和备份的时候不一样,比如test2
# nodejs操作mongoDB数据库
# 1】新建项目安装依赖
#新建项目
mkdir mongoproject
cd mongoproject
#创建npm
npm init
#安装依赖
npm install mongodb --save
# 2】引入模块
//app.js
const { MongoClient } = require('mongodb')
//连接url
const url = 'mongodb://localhost:27017';
//数据库名
const dbName = 'mongoproject'
//创建mongo服务
const client = new MongoClient(url, { useUnifiedTopology: true });
//使用连接方法连接服务
client.connect(function (err) {
if (err) return
console.log('数据库连接成功');
const db = client.db(dbName);
//返回的db对象进行数据库的操作
//1、查找数据
db.collection('orders')
.find({}).toArray((err, data) => {
if (err) return
console.log(data)
//异步操作,操作数据库完毕以后一定要 关闭数据库连接
client.close()
})
//2、增加数据
db.collection('orders')
.insertOne(
{ 'orderId': '000', 'name': 'order1' },
(err, result) => {
if (err) return
console.log('增加成功', result.insertedId)
client.close()
})
//3、修改数据
db.collection('orders')
.updateOne(
{ 'orderId': '000' },
{ $set: { "name": 'order2' } },
(err, result) => {
if (err) return
console.log('修改成功', result)
client.close()
})
//4、删除一条数据
db.collection('orders')
.deleteOne(
{ 'orderId': '000' },
(err, result) => {
if (err) return
console.log('删除一条数据成功', result)
client.close()
})
//5、删除多条数据
db.collection('orders')
.deleteMany(
{ 'orderId': '000' },
(err, result) => {
if (err) return
console.log('删除多条数据成功', result)
client.close()
})
})
# 3】在node服务中连接数据库
每次请求都是用的相同的实例client
const http = require('http')
const app = require('./module/route')
const { MongoClient } = require('mongodb')
const url = 'mongodb://localhost:27017'
const dbName = 'rayhomie'
//此时,每次请求都是用的相同的实例client
const client = new MongoClient(url, { useUnifiedTopology: true })
//注册web服务
http.createServer(app).listen(3000);
//配置路由
app.get('/',(req,res)=>{
client.connect((err)=>{
if(err){
console.log(err);
return;
}
const db =client.db(dbName)
//查询数据
db.collection('user').find({}).toArray((err,data)=>{
if(err) return;
console.log(data)
client.close()//操作数据库之后一定要关闭连接
res.send(data)
})
})
})
每次请求都创建新的client实例
const http = require('http')
const app = require('./module/route')
const { MongoClient } = require('mongodb')
const url = 'mongodb://localhost:27017'
const dbName = 'rayhomie'
//注册web服务
http.createServer(app).listen(3000);
//配置路由
app.get('/',(req,res)=>{
//每次请求都会重新创建新的实例
MongoClient.connect(url,(err,client)=>{
if(err){
console.log(err);
return;
}
const db =client.db(dbName)
//查询数据
db.collection('user').find({}).toArray((err,data)=>{
if(err) return;
console.log(data)
client.close()//操作数据库之后一定要关闭连接
res.send(data)
})
})
})