文章目录
MongoDB优势:面向开发者的易用,高效数据库。
- 简单直观:以自然方式来建模,已直观的方式来与数据库交互。
- 一目了然的对象模型
- 结构灵活:弹性模式从容响应需求的频繁变化。
- 多形性:同一个集合中可以包含不同字段(类型)的文档对象。
- 动态性:线上修改数据模式,修改时应用与数据库均无需下线。
- 数据治理:支持使用JSON Schema来规范数据模式。在保证模式灵活动态的前提下,提供数据治理能力。
- 快速开发:做更多的事,写更少的代码。
- JSON模型之快速特性:
- 数据库引擎只需要在一个存储区读写。
- 反范式、无关联的组织极大优化查询速度。
- 程序API自然,开发快速。
- JSON模型之快速特性:
MongoDB优势:原生的高可用和横向拓展能力
- Replica Set(分片) -2 to 50 个成员。
- 自恢复。主节点出现故障恢复到从节点
- 多中心容灾能力。
- 滚动服务 - 最小化服务终端。
MongoDB优势:横向拓展能力
- 需要的时候无缝拓展
- 应用全透明
- 多种数据分布策略
- 轻松支持TB-PB数量级
1.MongoDB技术优势总结
- Json结构和对象模型接近,开发代码量低。
- Json 的动态模型意味着更容易响应新的业务需求
- 复制集提供99.999%高可用
- 分片架构支持海量数据和无缝扩容
2. 下载安装
https://www.mongodb.com/try/download
3.MongoShell 的使用
mac下启动local
## usr/local下在mongo下的新建终端
mongod --dbpath data --logpath log/mongod.log --logappend
mongo数据库启动,不要关终端
新建一个终端窗口
mongo
mongo是MongoDB的交互式JavaScript Shell界面,它为系统管理员提供了强大的页面,并为开发人员提供了直接测试数据库查询和操作的方法。
## 指定端口
mongo --port=27017## 默认
## 指定 主机地址
mongo --host=127.0.0.1## default
## 查看帮助页面
mongo --help
## tips: 直接启动
mongo
## 运行后:
## 展示所有数据库
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
mock 0.000GB
## 使用mock
> use mock
switched to db mock
## 展示集合
> show collections
mock
3.1 javascript支持
mongo shell是基于javascript语法的,mongodb使用spidermonkey作为其内部的javascript解释器引擎,火狐提供了js内核解释器。
3.2 mongo shell命令
1. 数据库操作
show dbs
## 选择和创建数据库 没有会创建
use test
## 集合相当于关系数据库的表
show tables
## 两个命令作用相同
show collections
## 删除数据库
db.dropDatabase()
## 查看数据库版本
db.version()
- 数据库命名规则
- 不能是空字符串 ("")
- 不能含有空格、. 、$、/ 、\ 、\0
- 应全部小写
- 最多64字节
- 特殊作用的数据库
- admin :root数据库,一些特定服务端命令只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
- local:这个数据库永远不会被复制,可以用来存储限于本地单台服务器的任意集合。
- config:当mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
创建一个数据库后,查看数据库
> use test
switched to db test
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
mock 0.000GB
## 虽然没有持久化但是内存中存在
> db
test
发现并没有出现新创建的数据库
原因:
mongodb的存储分为两部分
- 内存
- 磁盘
创建的时候存放在内存中,并没有持久化到磁盘中。当数据库中创建集合的时候才会持久化到磁盘。
2. 集合操作
- 显示创建
- 隐式创建,直接插入文档,集合不存在就自动创建
集合命名规范:
- 集合名不能是空字符串“”。
- 集合名不能\0 字符(空字符)
## 查看集合
show collections
## 创建集合 (显示创建)
> db.createCollection("emp")
{ "ok" : 1 }
## 删除集合
> db.emp.drop()
true
## 查看集合详情
db.集合名.stats()
## 删除集合
db.集合名.drop()
## 显示集合名的帮助信息
db.集合名.help()
创建集合的参数:当集合不存在集合中插入文档会创建集合。
## 语法
> db.createCollection("name",options)
## capped 布尔 可选
## true 创建固定的集合。达到最大值自动覆盖最早的文档
> db.createCollection("emp",true,128,128)
{ "ok" : 1 }
## size 数值 可选 capped为true要指定
## 给集合指定一个最大值(字节)
> db.createCollection("emp",true,128,128)
{ "ok" : 1 }
## max 可选
## 指固定集合中包含文档的最大数量。
> db.createCollection("emp",true,128,128)
{ "ok" : 1 }
3.文档的增删改查
文档(document)的数据结构和JSON基本一样。
所有储存在集合中的数据都是BSON格式。
插入
(1)单个文档的插入,使用insert或者sava()方法向集合中插入文档
- 参数
- document:要插入到集合中的文档,或文档数组。(json格式)
- writeConcern:可选,类型是document。性能和可靠性的级别。
- ordered:boolean 可选。
- 如果为真则按插入顺序插入文档,如果一个文档出现错误,mongodb将返回而不处理数组中的其余文档。
- 如果为假,则执行无序插入,如果其中一个文档出现错误,则继续处理数组中的主文档。目前5版本默认为true.
db.collection.insert(
<document or array of documents>,
{
writeConcern:<document>,
ordered:<boolean>
}
)
要想comment的集合(表)中插入一条测试数据:
MongoDB Enterprise > db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date(),"likenum":NumberInt(10),"state":null})
WriteResult({ "nInserted" : 1 }) ## 表示插入成功
(2)批量插入(多个文档插入)
db.collection.insertMany(
[ <document 1> , <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
db.comment.insertMany([
{"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
{"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"}
]);
批量查询可能失败,可以用try catch进行异常捕获处理。(某文档出错mongodb不会回滚,所以try catch是比较好的选择)
try {
db.comment.insertMany([
]);
} catch (e) {
print (e);
}
基本查询
(1)查询所有
// comment 是集合名称
db.comment.find()
db.comment.find({userid:'1001'})
// 只返回第一条数据
db.comment.findOne({userid:'100001'})
(2)投影查询:查询结果返回部分字段
// 查询userid为"1003"的userid和nickname
MongoDB Enterprise > db.comment.find({userid:"1003"},{userid:1,nickname:1})
{ "_id" : "4", "userid" : "1003", "nickname" : "凯撒" }
{ "_id" : "5", "userid" : "1003", "nickname" : "凯撒" }
// 默认展示 _id ,取消显示
MongoDB Enterprise > db.comment.find({userid:"1003"},{userid:1,nickname:1,_id:0})
{ "userid" : "1003", "nickname" : "凯撒" }
{ "userid" : "1003", "nickname" : "凯撒" }
更新
语法:
/**
query:查询条件,将文档查询出来
update:更新条件
options:附带选项
*/
db.collection.update(query, update, options)
//或
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2
}
)
(1)覆盖的修改
//在comment集合中修改_id为1的点赞量为1001
/**
数据
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("2019-08-05T22:08:15.522Z"), "likenum" : 1000, "state" : "1" }
提示:默认是浮点数
**/
db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
//整条数据被覆盖只剩id
(2) 局部修改,使用修改器
//默认只修改第一条数据
db.comment.update({userid:"1003"},{$set:{nickname:"凯撒2"}})
//修改所有符合条件的数据 需要加第三个参数
db.comment.update({userid:"1003"},{$set:{nickname:"凯撒大帝"}},{multi:true})
(3)列值增长的修改
// 将likenum增长1
db.comment.update({_id:"3"},{$inc:{likenum:NumberInt(1)}})
删除文档
语法:
db.集合名.remove(条件)
// 将数据完全删除
db.comment.remove({})
// 删除id=1的记录
db.comment.remove({_id:"1"})
4.文档的分页查询
1. 统计查询
db.collection.count(query, options)
// 统计comment集合的所有的记录数
db.comment.count()
// 统计userid为1003的记录条数
db.comment.count({userid:"1003"})
2.分页列表查询
基本语法:
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
// 查询前3条数据
db.comment.find().limit(3)
// 跳过前三条数据
db.comment.find().skip(3)
// 每页显示两个
//第一页
db.comment.find().skip(0).limit(2)
//第二页
db.comment.find().skip(2).limit(2)
//第三页
db.comment.find().skip(4).limit(2)
3.排序查询
用sort()方法可以通过参数指定排序字段
-
1为升序排列
-
-1为降序排列
-
语法:
db.COLLECTION_NAME.find().sort({KEY:1}) 或 db.集合名称.find().sort(排序方式)
// 对userid降序排列,并对访问量进行升序排列
db.comment.find().sort({userid:-1,likenum:1})
// 投影查询
db.comment.find({},{userid:1}).sort({userid:1})
Skip(),limit(),sort的执行顺序
- skip()
- limit()
- sort()
与命令的编写顺序无关。
5.文档的更多查询
1. 正则的复杂条件查询
语法:
db.collection.find({field:/正则表达式/})
或
db.集合.find({字段:/正则表达式/})
正则表达式是js语法
// 查询包含“开水”的所有文档
db.comment.find({content:/开水/})
// 查询内容以“专家”开头的
db.comment.find({content:/^专家/})
2.比较查询
语法:
- < $gt
- <= $lte
- ‘>’ $gt
- ‘>=’ $gte
- != $ne
db.集合名称.find({ "field" : { $gt: value }}) // 大于: field > value
db.集合名称.find({ "field" : { $lt: value }}) // 小于: field < value
db.集合名称.find({ "field" : { $gte: value }}) // 大于等于: field >= value
db.集合名称.find({ "field" : { $lte: value }}) // 小于等于: field <= value
db.集合名称.find({ "field" : { $ne: value }}) // 不等于: field != value
例子:
// 查询评论点赞数量大于700的记录
db.comment.find({likenum:{$gt:NumberInt(700)}})
3. 包含查询
使用$in操作符
// 查询评论的集合中userid字段包含1003或1004的文档
db.comment.find({userid:{$in:["1003","1004"]}})
// 查询评论集合中userid字段不包含1003和1004的文档
db.comment.find({userid:{$nin:["1003","1004"]}})
4.条件链接查询
查询同时满足两个以上条件,需要使用$and操作符条件进行关联
$and:[ { },{ },{ } ]
//查询评论集合中likenum大于等于700 并且小于2000的文档:
db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]})
或者的关系
$or:[ { },{ },{ } ]
//查询评论集合中userid为1003,或者点赞数小于1000的文档记录
db.comment.find({$or:[ {userid:"1003"} ,{likenum:{$lt:1000} }]})
总结
选择切换数据库:use articledb
插入数据:db.comment.insert({bson数据})
查询所有数据:db.comment.find();
条件查询数据:db.comment.find({条件})
查询符合条件的第一条记录:db.comment.findOne({条件})
查询符合条件的前几条记录:db.comment.find({条件}).limit(条数)
查询符合条件的跳过的记录:db.comment.find({条件}).skip(条数)
修改数据:db.comment.update({条件},{修改后的数据}) 或db.comment.update({条件},{$set:{要修改部分的字段:数据})
修改数据并自增某字段值:db.comment.update({条件},{$inc:{自增的字段:步进值}})
删除数据:db.comment.remove({条件})
统计查询:db.comment.count({条件})
模糊查询:db.comment.find({字段名:/正则表达式/})
条件比较运算:db.comment.find({字段名:{$gt:值}})
包含查询:db.comment.find({字段名:{$in:[值1,值2]}})或db.comment.find({字段名:{$nin:[值1,值2]}})
条件连接查询:db.comment.find({$and:[{条件1},{条件2}]})或db.comment.find({$or:[{条件1},{条件2}]})
练习
db.student.save({_id:1,classid:1,age:18,name:"little1",love:["football","swing","cmpgame"]});
db.student.save({_id:2,classid:2,age:19,name:"little2",love:["play"]});
db.student.save({_id:3,classid:2,age:20,name:"little3"});
db.student.save({_id:4,classid:1,age:21,name:"little4"});
db.student.save({_id:5,classid:1,age:22,name:"little5",opt:"woshisheia"});
db.student.save({_id:6,classid:2,age:23,name:"little4"});
1、查询 name为little1的学生,并且只显示 age,name两个字段
db.student.find({name:"little1"},{name:1,age:1})
2、查询 name为little1,age为18的学生,并且只显示 age,name,love三个字段
db.student.find({name:"little1",age:18},{name:1,age:1,love:1})
3、查询从第二条文档开始的3条文档
db.student.find().skip(1).limit(3);
4、按age升序排序
*db.student.find().sort({age:1});*
5、查询 name为little3或age为19的学生
db.student.find({‘$or‘:[{name:‘little3‘},{age:19}]})
6、查询出19<age<=21的数据
db.student.find({age:{$gt:19,$lte:21}});
7、查询出存在opt字段的数据
db.student.find({opt:{$exists:true}});
8、查询出name不为little2的数据
db.student.find({name:{$ne:"little2"}});
9、查询出age为16,18,19的数据
db.student.find({age:{$in:[16,18,19]}});
10、查询出age不为16,18,19的数据
db.student.find({age:{$nin:[16,18,19]}});
11、查询classid为2并且age为20 或者name为little2的学生
db.student.find({‘$or‘:[{classid:2,age:2},{name:"little2"}]})
12、查询age小于等于20或者大于22的文档
db.student.find({‘$or‘:[{age:{$lte:20}},{age:{$gt:22}}]})
向数据库users中插入如下的文档
var user1 = {
name: "xiaobu",
comments: [{userId: "001", content: "评论1"},{ userId: "002",content: "评论2"},{userId: "003",content: "评论3"}],
favorites : {books: [ "西游记", "红楼梦", "三国演义", "水浒传"] },
age: 26.0
};
var user2 = {
name:"juyi",
comments:[{userId:"101",content: "评论1"},{userId: "102",content: "评论2"}],
favorites:{ movies:["肖生克的救赎", "阿甘正传", "头号玩家"]},
age: 25.0
};
var user3 = {
name: "tom",
favorites: {movies: [ "头号玩家", "肖生克的救赎", "阿甘正传" ]},
age: 18.0
};
var user4 = {
name: "tom",
favorites: {movies: [ "头号玩家", "肖生克的救赎", "阿甘正传" ]},
age: 18.0
};
更新操作:
1、为name为 juyi的文档增加country字段,值为china
db.users.update({name:"juyi"},{$set:{country:"china"}})
2、为所有文档的favorites字段中 增加一个字段fruit 值为一个数组[apple,banana]
db.homework1.update({},{$set:{fruit:[“apple","banana"]}},{multi:true})
3、更新age小于18或者age大于24的文档,删除文档中movies数组中的最后一个元素
db.homework1.update({$or:[{age:{$lt:18}},{age:{$gte:24}}]},{$pop:{"favorites.movies":-1}})
4、向name为tom文档的fruit的数组中增加两个元素 grapes、watermelon,然后取其数组的后三个元素(只更新查询到第一条文档)
db.homework1.update({name:”tom"},{$push:{fruit:{$each:["grapes","watermelon"],$slice:-3}}})
5、向存在favorites.books数组字段的文档中,在books数组的第二个元素位置添加元素“MongoDB”,“NoSQL”,并且数组元素按照升序排序
db.homework1.update({“favorites.books":{KaTeX parse error: Expected 'EOF', got '}' at position 12: exists:true}̲},{push:{“favorites.books”:{ e a c h : [ " M o n g o d b " , " N o S q l " ] , each:["Mongodb","NoSql"], each:["Mongodb","NoSql"],position:1,$sort:1}}})
查询:
1、查询comments字段不存在的文档
db.homework1.find({comments:{$exists:false}})
2、查询favorites.movies中,有”头号玩家”和”肖生克的救赎”的数据
db.homework1.find({“favorites.movies":{$all:["头号玩家","肖生克的救赎"]}})
3、查询name存在”bu”字符,并且age小于20或者大于24(要求使用regex操作符)
db.homework1.find({$and:[{name:{$regex:/bu/}},{$or:[{age:{$lt:20}},{age:{$gt:24}}]}]})
4、查询userId=”101”并且其评语为”评论1”的文档(注意userId的数据类型)
db.homework1.find({comments:{$elemMatch:{userId:”101",content:"评论1"}}})
5、查询name=”xiaobu”的文档,并且只显示comments前三条数据
db.homework1.find({name:”xiaobu"},{comments:{$slice:[0,3]}})
6、查询所有name=”xiaobu”,且comments只显示第2条的评论,且只显示comments和id字段,其它信息不显示
db.homework1.find({name:”xiaobu"},{comments:{$slice:[1,1]},_id:1})
7、查询被userId=101或者userId=001评论过的数据
db.homework1.find({"comments.userId":{$in:["101","001"]}})