学习MongoDB

MongoDB——分布式文件存储数据库
C++语言编写
支持的数据结构很松散,类似于json的bson格式

启动服务
net start mongodb

登录(验证是否安装成功)
e:
cd mongodb/bin
在E:\mongodb\bin目录下输入mongo
退出就是exit

数据库(database) 集合(collection) 文档/数据(document)
查看数据库:
show databases/show dbs

选择数据库:
use 数据库名称

在mongodb中选择不存在的数据库不会报错
隐式创建:后期当该数据库有数据时,系统会自动创建

查看集合
show collections

创建集合
db.createCollection(’集合名‘)

删除集合
db.集合名.drop()

删除数据库
1.通过use语法选择数据库
2.通过db.dropDatabase()删除数据库

数据插入
db.集合名.insert(JSON数据)
集合存在-直接插入数据,集合不存在-隐式创建
use test2
db.c1.insert({webopenfather:“webopenfather”,age:18})

数据库和集合不存在时都隐式创建
对象的键统一不加引号方便查看,但是查看集合数据时系统会自动加。

查看集合
db.集合名find()

mongodb会给每条数据增加一个全球唯一的_id键
_id的组成
时间戳 机器码 PID 计数器

可以自定义id,只需要给插入的JSON数据增加_id键即可覆盖
但不推荐!
db.c1.insert({_id:1,uname:‘pingping’})

一次性插入多条记录
-传递数组,数组中写一个个JSON数据即可
db.c1.insert([
{uname:‘z3’,age:3}
{uname:‘l4’,age:5}
{uname:‘w5’,age:5}
])
一次性插入三条数据

快速插入十条数据
mongodb底层使用js引擎实现,所以支持部分js语法
因此,可以写for循环
for(var i=1; i<=10;i++){
print(i)
}
需求:在test2数据库c3集合中插入十条数据,分别为a1,a2…a10
for(var i = 1; i <= 10;i++){
db.c3.insert({uname:‘a’+i,age:i})
}
for循环是一条一条执行,前面的执行提示看不见,只出现最后一条

集合查询
db.集合名.find(条件,[查询的列])
条件
查询所有数据 {}或者不写
查询age=6的数据 {age:6}
既要age=6又要性别=男{age:6,sex:‘男’}
查询的列(可选参数)
不写 查询全部列(字段)
{age:1}只显示age列
{age:0}除了age列(字段都显示)
不管怎么写,系统自定义的_id都会在

只查询所有uname

查询年龄大于五岁的数据
db.集合名.find({
键:{运算符:值}
})
运算符
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
$in in
$nin not in

查询年龄为5、8、10岁的值

只看年龄列或者年龄以外的列

数据修改语法
db.集合名.update(条件,新数据,[是否新增,是否修改多条])
是否新增:
指条件匹配不到输入,true为插入,false为不插入
是否修改多条:
将匹配到的多条数据都修改:true修改所有的匹配成功的数据,false只修改一条数据
准备工作
use test2
for(var i = 1; i<= 10; i++){
db.c3.insert({“uname”:“zs”+i,“age”:i})
}
将uname为zs1的数据改为zs2
db.c3.update({uname:‘zs1’},{uname:‘zs2’})
发现不是修改而是替换,新的数据只有_id和uname了
db.c3.update({uname:‘zs1’},{$set:{uname:‘zs2’}})
解决:
db.集合名.update(条件,
{修改器:{键:值}})
修改器:
$inc 递增
$rename 重命名列
$set 修改列值
$unset 删除列

使用修改器将zs2的姓名修改为zs22
db.c3.update({uname:‘zs2’},{$set:{uname:‘zs22’}})

给uname为zs10的年龄增加两岁或者减少两岁
db.c3.update({uname:‘zs10’},{KaTeX parse error: Expected 'EOF', got '}' at position 12: inc:{age:2}}̲) db.c3.update(…inc:{age:-2}})

一次性写多个修改器
db.c4.update({uname:‘神龙教主’},{
$set:{uname:‘pingping’},
$inc:{age:111},
$rename:{who:‘age’}
$unset(other:true)
})

是否新增,默认是false,条件不匹配也不新增
设置为true时,查找条件不匹配新增一个
db.c3.update({uname:‘zs30’},{$set:{age:30}},true)

是否修改多条数据,默认是false
db.c3.update({uname:‘zs4’},{$set:{age:444}},true,true)

文档删除
db.集合名.remove(条件,[是否删除一条])
true:删除一条,false:删除多条
默认删除多条

总结CURD
增加Create
db.集合名.insert(JSON数据)
删除Delete
db.集合名.remove(条件,[是否删除一条(默认false,删除多条)])
改Update
db.集合名.update(条件,新数据,[是否新增,是否修改多条])
升级语法
db.集合名.update(条件,{修改器:{键:值}})
查Read
db.集合名.find(条件,[查询的列])

清空dos
cls

use school
for (var num=1; num <= 20; num++){
db.stu.insert({
id:num,
no:‘QF’+num,
uname:‘神龙教’+num,
tel:‘11111111’,
sex:‘女’,
age:num,
school:‘研究生’,
remark:‘土豪’
})
}

格式化展示数据
db.stu.find().pretty()

db.c1.insert([
{_id:1,name:“a”,sex:1,age:1},
{_id:2,name:“a”,sex:1,age:2},
{_id:3,name:“b”,sex:2,age:3},
{_id:4,name:“c”,sex:2,age:4},
{_id:5,name:“d”,sex:2,age:5},
])

排序
db.集合名.find().sort(JSON数据)
键-就是要排序的字段,值:1升序,-1降序
按年龄升序
db.c1.find().sort({age:1})
按年龄降序
db.c1.find().sort({age:-1})

db.集合名.find().sort().skip(数字).limit(数字)
skip跳过指定数量
limit限制查询的数量

降序查询两条数据
db.c1.find().sort({age:-1}).limit(2)
降序跳过两条并查询两条数据
db.c1.find().sort({age:-1}).skip(2).limit(2)

数据库共有十条数据,每页显示两条数据
1页 1 2
5页 9 10
skip计算公式:(当前页-1)*每页显示条数
limit(2)
count():统计总数量

聚合查询
把数据聚在一起,然后统计
db.集合名词.aggregate([
{管道:{表达式}}
])

常用管道
$group 将集合中的文档分组,用于统计结果
$match 过滤数据,只输出符合条件的文档
$sort 聚合数据进一步排序
$skip 跳过指定文档数
$kimit 限制集合数据返回文档数
常用表达式
$sum 总和 $sum:1同count表示统计
$avg 平均
$min 最小值
$max 最大值

统计男生、女生的总年龄
db.c1.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{ _id:"sex",
rs:{ s u m : " sum:" sum:"age"}
}
}
])

统计男生、女生的总人数
db.c1.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{ _id:"sex",
rs:{$sum:1}
}
}
])

求学生总数和平均年龄
db.c1.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: …ll, total_num:{sum:1},
total_avg:{ a v g : " avg:" avg:"age"},
}
}
])

查询男生、女生人数,按人数升序
db.c1.aggregate([
{管道:{表达式}},
{管道:{表达式}}
])
db.c1.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{ _id:"sex",
rs:{$sum:1}
}
},
{
$sort:{rs:1}
}
])

MongoDB索引
索引是一种排序好的便于快速查询的数据结构
作用:帮助数据库高效地查询数据

索引
优点
提高数据查询的效率,降低数据库的IO成本
通过索引对数据进行排序,降低数据排序的成本,降低CPU消耗
缺点
占用磁盘空间
大量索引影响SQL语句效率,因为每次插入和修改数据都需要更新索引

语法:
db.集合名.createIndex(待创建索引的列,[额外的选项])
参数:
待创建索引的列:{键:1,…,键:-1}
1升序,-1降序
{age:1}表示创建age索引并按照升序的方式存储
额外选项:设置索引的名称或者唯一索引

删除索引语法:
全部删除:db.集合名.dropIndexes()
删除指定:db.集合名.dropIndex(索引名)

查看索引语法
db.集合名.getIndexes()

for(var i=0;i<100000;i++){
db.c1.insert({name:‘aaa’+i,age:i});
}

统计一个集合里面有多少条数据
db.集合名.count()

给name添加普通索引
db.c1.createIndex({name:1})

查看当前索引
会自动创建名字:name_1
_id索引是默认的
key:为哪个列创建了索引
name:表示索引名,默认系统生成,也可以自定义

删除name索引
db.c1.dropIndex(‘name_1’)

给name创建索引并起名pingping
db.c1.createIndex({name:1},{name:“pingping”})

MongoDB是存储文档的非关系型数据库
数据库>集合>文档,存储JSON
同一集合的文档可以描述不同的字段

Mongo Shell支持JavaScript

存储在MongoDB的每一篇文档,都有一个专属的id
称为:文档主键_id
文档逐渐_id具有唯一性
对象主键ObjectId是默认的文档主键

创建文档
db.集合名.insert()
db.集合名.save()

创建单个文档
db.collection.insertOne()

“acknowledged”:true表示安全写级别被启用
insertId:显示了被写入文档的_id

处理抛出的错误,将要输入的命令包在try内
try{
db.account.insertOne(
{
_id:“account1”,
name:“bob”,
balance:50
}
)
}catch(e){
print(e)
}

创建多个文档
db.collection.insertMany([
{
name:“charlie”,
balance:500
},
{
name:“david”,
balance:200
}
])

在乱序写入时遇到错误
try{
db.accounts.insertMany([
{
_id:“account1”,
name:“edwrad”,
balance:700
},
{
name:“fred”,
balance:20
}
],{ordered:false})
}catch(e){
print(e)
}

db.coolection.insertMany()
在顺序写入时,一旦遇到错误,操作便会退出
剩余的文档无论是否正确,都不会被写入
在乱序写入时,即使某些文档造成了错误,剩余的文档仍然会被写入

创建单个或多个文档都可以
db.collection.insert()

db.accounts.insert(
{
name:“george”,
balance:1000
}
)

写入文档的数量为1

inserOne()和insertMang()不支持db.collection.explain()命令
insert()支持db.collection.explain()

可以从默认的对象主键objectId中提取ObjectId的创建时间

ObjectId(“616f7f6c95e3f8072f8de9eb”).getTimestamp()
ISODate(“2021-10-20T02:31:08Z”)

复合主键
可以使用文档作为另一个文档的主键

db.accounts.insert(
{
_id:{accountNo:“001”,type:“savings”},
name:“irene”,
balance:80
}
)
当调换复合主键中字段的位置,也可以再次写入文档
db.accounts.insert(
{
_id:{type:“savings”,accountNo:“001”},
name:“irene”,
balance:80
}
)

读取文档
db.collection.find()
查询操作返回的结果游标

清楚的显示所有的文档
db.accounts.find().pretty()

读取alice的银行账户文档
db.accounts.find({name:“alice”})
相等于
db.accounts.find({name:{$eq:“alice”}})

读取alice的用户且余额是100元的银行账户文档
db.accounts.find({name:“alice”,balance:100})

读取银行账户类型为存储账户的文档(复合主键查询)
db.accounts.find({"_id.type":“savings”})

读取不属于alice的银行账户的文档
db.accounts.find({name:{$ne:“alice”}})
$ne也会筛选出不包含查询字段的文档

读取余额不少于100的银行账户
db.accounts.find({balance:{$gte:100}})

读取用户名字排在fred之前的银行账户文档
db.accounts.find({name:{$lt:“fred”}})

读取alice和bob的银行账户
db.accounts.find({name:{$in:[“alice”,“bob”]}})

读取除了alice和bob之外的银行账户
db.accounts.find({name:{$nin:[‘alice’,‘bob’]}})

KaTeX parse error: Expected '}', got 'EOF' at end of input: …d({"_id.type":{nin:[“savings”]}})

$not匹配筛选条件不成立的文档
$and匹配多个筛选条件全部成立的文档
$or匹配至少一个筛选条件成立的文档
$nor匹配多个筛选条件全部不成立的文档

读取余额不小于500的银行账户文档
KaTeX parse error: Expected '}', got 'EOF' at end of input: …find({balance:{not:{$lt:500}}})

读取余额大于100并且用户姓名排在alice之后的银行账户
db.accounts.find({
KaTeX parse error: Expected '}', got 'EOF' at end of input: …nd:[ {balance:{gt:100}},
{name:{$gt:‘alice’}}
]
})

当筛选条件应用在不同字段上,可以省略KaTeX parse error: Expected '}', got 'EOF' at end of input: …ind({ balance:{gt:100},
name:{$gt:‘alice’}
})

当筛选条件应用在同一个字段上时,也可以简化命令
读取余额大于100,小于2000的银行账户
db.accounts.find({balance:{ g t : 100 , gt:100, gt:100,lt:2000}})

读取属于alice或者charlie的银行账户文档
db.accounts.find({
KaTeX parse error: Expected '}', got 'EOF' at end of input: or:[ {name:{eq:‘alice’}},
{name:{$eq:‘charlie’}}
]
})

读取余额小于100或者大于500的银行账户文档
db.accounts.find({
KaTeX parse error: Expected '}', got 'EOF' at end of input: or:[ {balance:{lt:100}},
{balance:{$gt:500}}
]
})

读取既不属于alice和charlie且余额不大于100的银行账户文档
db.accounts.find({
KaTeX parse error: Expected '}', got 'EOF' at end of input: …e"}, {balance:{gt:100}}
]
})

字段操作符
$exists 匹配包含查询字段的文档
$type 匹配字段类型符合查询值的文档

读取包含账户类型字段的文档
db.accounts.find({"_id.type":{$exists:true}})

查询不是checking类型的文档
db.accounts.find({"_id.type":{ n e : " c h e c k i n g " , ne:"checking", ne:"checking",exists:true}})

读取文档主键是字符串的文档
db.accounts.find({_id:{$type:“string”}})

对象主键的类型:“objectId”
复合主键的类型:“object”
读取文档主键是对象主键或者复合主键的文档
db.accounts.find({_id:{$type:[“objectId”,“object”]}})

类型还有为"null"的
读取用户姓名为null的文档
db.accounts.find({name:{$type:“null”}})

db.accounts.insert([
{
name:“jack”,
balance:2000,
contact:[“1111111”,“Alabama”,“US”]
},
{
name:“karen”,
balance:2500,
contact:[[“222222222”,“33333333”],“Beijing”,“China”]
}
])

$all匹配数组字段中包含所有查询值的文档
$elemMatch匹配数组字段中至少存在一个值满足筛选条件的文档

读取联系地址位于中国北京的文档
db.accounts.find({contact:{$all:[“China”,“Beijing”]}})

读取联系电话包含 “222222222”,"33333333"的文档
db.accounts.find({contact:{$all:[[“222222222”,“33333333”]]}})

读取联系电话范围在1000000到2000000之间的文档
db.accounts.find({contact:{KaTeX parse error: Expected '}', got 'EOF' at end of input: elemMatch:{gt:“1000000”,$lt:“2000000”}}})

包含一个在200000000和300000000之间,和一个30000000和40000000之间联系电话的文档
db.accounts.find({
contact:{KaTeX parse error: Expected '}', got 'EOF' at end of input: all:[ {elemMatch:{ g t : " 200000000 " , gt:"200000000", gt:"200000000",lt:“300000000”}},
{KaTeX parse error: Expected '}', got 'EOF' at end of input: elemMatch:{gt:“30000000”,$lt:“40000000”}}
]}
})

r e g e x 匹 配 满 足 正 则 表 达 式 文 档 在 和 regex匹配满足正则表达式文档 在和 regexin操作符一起使用时,只能使用/pattern/

读取用户姓名以c或者j开头的银行账户文档
db.accounts.find({name:{$in:[/c/,/j/]}})

读取用户姓名包含ACK(不区分大小写)的银行账户文档
db.accounts.find({name:{ r e g e x : / A C K / , regex:/ACK/, regex:/ACK/,options:‘i’}})
$options:'i’不区分大小写ignorecase

db.collection.find()返回一个文档集合游标
在不迭代游标的情况下,只列出前20个文档

var myCursor = db.accounts.find()
myCursor
只会打印出前20个文档

可以使用游标下标直接访问文档集合中的某一个文档
myCursor[1]

遍历完游标中所有的文档之后,游标就会自动关闭
或者在10分钟之后,游标会自动关闭

可以使用noCursorTimeout()函数保持游标一直有效
var myCursor = db.accounts.find().noCursorTimeout()
在这之后,如果遍历整个游标,游标还是会关闭
在不遍历游标的情况下,需要主动关闭游标
myCursor.close()

游标函数
cursor.hasNext()
cursor.next()
cursor.forEach()
cursor.limit()
cursor.skip()
cursor.count()
cursor.sort()

var myCursor = db.accounts.find();
while(myCursor.hasNext()){
… printjson(myCursor.next());
… }

var myCursor = db.accounts.find();
myCursor.forEach(printjson)
遍历游标所指的每一个文档

只返回第一个文档
db.accounts.find().limit(1)

跳过所有文档中的第一篇文档
db.accounts.find().skip(1)

db.account.find().limit(0)
相当于不适用limit()函数,返回所有文档

cursor.count()
在默认情况下,为false
不会考虑limit()和skip()的效果

db.accounts.find().limit(1).count()
7
db.accounts.find().limit(1).count(true)
1

db.accounts().find().count()
在不提供筛选条件时,count()并不会去遍历整个文档
而是从集合的元数据Metadata中取得结果
当数据库分布式结构较为复杂时,元数据中的文档数量可能不准确
在这种情况下,应该避免应用不提供筛选条件的cursor.count()函数
而使用聚合管道计算文档数量

按照余额从大到小,用户姓名按字母排序的方式文档
db.accounts.find().sort({balance:-1,name:1})

读取余额最大的银行账户文档
db.accounts.find().sort({balance:-1}).limit(1)

cursor.skip()永远会在cursor.limit()之前执行

db.accounts.find().limit(5).skip(3)
最终的结果是五个文档

cursor.sort()永远在cursor.skip()和cursor.limit()之前执行

db.accounts.find().skip(3).limit(5).sort({balance:-1})

游标函数的应用顺序是sort(),skip(),limit()

只返回银行账户文档中的用户姓名

db.accounts.find({},{name:1})
只返回银行账户文档中的用户姓名,且不包括文档主键
db.accounts.find({},{name:1,_id:0})
{ “name” : “alice” }
{ “name” : “bob” }

不返回银行账户文档中的用户姓名(也不返回文档主键)

db.accounts.find({},{name:0,_id:0})
{ “balance” : 100 }

除了文档主键之外,不可以在投影文档中混合使用包含和不包含两种投影操作

在数组字段上使用投影
KaTeX parse error: Expected '}', got 'EOF' at end of input: …ame:1,contact:{slice:1}})
返回数组中第一个元素

返回数组中倒数第一个字段
db.accounts.find({},{_id:0,name:1,contact:{$slice:-1}})

返回数组中的倒数两个字段
db.accounts.find({},{_id:0,name:1,contact:{$slice:-2}})

db.accounts.find({},{_id:0,name:1,contact:($slice:[1,2])})
[1,2]
skip(1)再limit(2)

e l e m M a t c h 和 elemMatch和 elemMatch操作符可以返回数组字段中满足筛选条件的第一个元素
db.accounts.find({},
{
_id:0,
name:1,
contact:{KaTeX parse error: Expected '}', got 'EOF' at end of input: elemMatch:{gt:“Alabama”}}
}
)

更新文档

db.accounts.find({name:“alice”})
{ “_id” : “account1”, “name” : “alice”, “balance” : 100 }
db.accounts.update({name:“alice”},{name:“alice”,balance:123})
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })
db.accounts.find({name:“alice”})
{ “_id” : “account1”, “name” : “alice”, “balance” : 123 }

文档主键_id是不可以更改的

查看账户余额在20到80之间的文档
db.accounts.find({balance:{ g t : 20 , gt:20, gt:20,lt:80}})

更新jack的银行账户余额和开户信息
db.accounts.update(
{name:“jack”},
{$set:
{
balance:3000,
info:{
dateOpened:new Date(“2021-10-20T16:00:00Z”),
branch:“branch1”},
}
}
)

更新内嵌文档的字段
db.accounts.update(
{name:‘jack’},
{$set:
{
“info.dateOpened”:new Date(“2021-10-20T16:20:00Z”),
}
}
)

更新数组内的字段
db.accounts.update(
{name:‘jack’},
{$set:
{“contact.0”:“666666666”}
}
)

添加jack的联系方式
db.accounts.update(
{name:‘jack’},
{$set:
{“contact.3”:“new contact”}
}
)

跳过一个位置,在数组中添加新元素
db.accounts.update(
{name:‘jack’},
{$set:
{“contact.5”:“another new contact”}
}
)
如果向现有数组字段范围以外的位置添加新值
数组字段的长度会扩大
未被赋值的数组成员将被设置为null

删除jack的银行余额和开户地点
db.accounts.update(
{name:‘jack’},
{$unset:
{
balance:" “,
“info.branch”:” ",
}
}
)

删除数组内的字段
db.accounts.update(
{name:“jack”},
{$unset:
{“contact.0”:""}
}
)

当使用$unset命令删除数组字段中的某一个元素时
这个元素不会被删除,只会被赋以null值,而数组的长度不会改变

当$rename命令中的新字段存在的时候
r e n a m e 会 先 rename会先 renameunset原字段
再$set新字段

db.accounts.update(
{name:“karen”},
{$set:
{
info:{
dateOpene:new Date(“2021-10-20T16:20:00Z”),
branch:“branch1”
},
“contact.3”:{
primaryEmail:“xxx@gmail.com”,
secondaryEmail:“yyy@gmail.com”
}
}
}
)

更新账户余额和开户地点字段在文档中的位置
db.accounts.update(
{name:‘karen’},
{$rename:
{
“info.branch”:“branch”,
“balance”:“info.balance”
}
}
)

重命名数组中内嵌文档的字段

$rename命令中的旧字段和新字段都不可以指向数组元素
s e t 和 set和 setunset命令可以指向数组元素

更新david的账户余额
db.accounts.update(
{name:“david”},
{KaTeX parse error: Expected 'EOF', got '}' at position 23: …balance:-0.5 } }̲ ) 乘以 db.accoun…mul:
{balance:0.5}
}
)
如果使用KaTeX parse error: Expected '}', got 'EOF' at end of input: …ame:"david"}, {inc:
{
notYetExist:10
}
}
)
如果使用$mul更新的字段不存在,会自动添加一个字段,并且这个字段值为0

db.accounts.find(
{name:“karen”},
{name:1,info:1,_id:0}
)

KaTeX parse error: Expected '}', got 'EOF' at end of input: …ame:"karen"}, {min:
{
“info.balance”:5000
}
}
)
KaTeX parse error: Expected '}', got 'EOF' at end of input: …ame:"karen"}, {max:
{
“info.balance”:5000
}
}
)

数组更新操作符
$addToSet 向数组中增添元素
$pop 从数组中移除元素
$pull 从数组中有选择性地移除元素

db.accounts.find(
{name:“karen”},
{name:1,contact:1,_id:0}
).pretty()
向karen的文档中添加联系方式
db.accounts.update(
{name:‘karen’},
{$addToSet:
{
contact:“China”
}
}
)
a d d T o S e t : 如 果 要 插 入 的 值 以 及 存 在 数 组 字 段 中 , addToSet:如果要插入的值以及存在数组字段中, addToSet,addToSet不会再添加重复值

删除数组中的最后一个元素
从karen的账户文档中删除最后一个联系方式
db.accounts.update(
{name:‘karen’},
{$pop:{contact:1}}
)
删除第一个元素
-1

$pul从数组字段中删除特定元素

将karen的账户文档复制为lawrence的账户文档
db.accounts.find(
{name:‘karen’},
{_id:0}
).forEach( function(doc) {
var newDoc = doc;
newDoc.name = “lawrence”;
db.accounts.insert(newDoc);
}
)

删除字段中包含hi的字符
db.accounts.update(
{name:“karen”},
{KaTeX parse error: Expected '}', got 'EOF' at end of input: pull:{contact:{regex:/hi/}}}
)

$pull:不要求字段排列顺序完全匹配
$pullAll:要求字段排列顺序完全匹配

$push更新操作,向数组字段中添加元素

对文档中的数组字段进行排序
db.accounts.update(
{name:“lawrence”},
{$push:{
newArray:{
$each:[],
sort:-1
}
}}
)

找到数组中的pos2,并替换为updated
db.accounts.update(
{
name:‘lawrence’,
newArray:‘pos2’
}
{KaTeX parse error: Expected '}', got 'EOF' at end of input: …et: {"newArray.":“updated”}
}
)

$[]指代数组字段中的所有元素

把所有联系电话改为888888888
db.accounts.update(
{name:‘lawrence’},
{KaTeX parse error: Expected '}', got 'EOF' at end of input: …: { "contact.0.[]":"88888888“
}
}
)

在默认情况下,update命令只更新一篇文档
使用multi选项更新多个符合筛选条件的文档

MongoDB只能保证单个文档操作的原子性
不能保证多个文档操作的原子性

upsert选项设置为true时,如果筛选条件没有匹配任何文档
会创建新文档
db.accounts.update(
{name:‘maggie’},
{$set:
{
balance:700
}
},
{upsert:true}
)

删除文档
db.collection.remove()

删除余额为50的银行账户文档
db.accounts.remove({balance:50})
默认情况下,remove命令会删除所有符合谁选条件的文档
如果只想删除满足筛选条件的第一篇文档,使用justOne选项

删除一篇余额小于100的文档
db.accounts.remove(
{balance:{$lt:100}},
{justOne:true}
)

删除集合内所有文档
db.accounts.remove({})

删除集合,可以删除整个集合,包括集合的文档以及集合的索引
db.collection.drop()

聚合管道
db.collection.aggregate()

$ 指示字段路径
$.指示内嵌文档字段路径
例如
$name指示银行账户文档中客户姓名的字段
$info.dateOpened指示银行账户文档中开户日期的字段

< v a r i a b l e > 指 示 系 统 变 量 <variable>指示系统变量 <variable>CURRENT指示管道中当前操作的文档

$ C U R R E N T . < f i e l d > 和 CURRENT.<field>和 CURRENT.<field>是等效的

$literal:-指示常量
l i t e r a l : " literal:" literal:"name"指示常量字符串"$name"

db.accounts.insertMany([
{
name:{firstname:“alice”,lastName:“wong”},
balance:50
},
{
name:{firstName:“bob”,lastName:“yang”},
balance:20
}
])

对银行账户文档进行重新投影
db.accounts.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: …1, clientName:"name.firstName"
}
}
])

db.accounts.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: …1, nameArray:["name.firstName",“ n a m e . m i d d l e N a m e " , " name.middleName"," name.middleName","name.lastName”]
}
}
])

$match文档筛选
db.accounts.aggregate([
{
$match:{
“name.firstname”:“alice”
}
}
])

db.accounts.aggregate([
{
$match:{
KaTeX parse error: Expected '}', got 'EOF' at end of input: or:[ {balance:{gt:50,$lt:80}},
{“name.lastName”:“yang”}
]
}
}
])

将筛选和投影阶段结合在一起
db.accounts.aggregate([
{
$match:{
KaTeX parse error: Expected '}', got 'EOF' at end of input: or:[ {balance:{gt:40,$lt:80}},
{“name.lastName”:“yang”}
]
}
},
{
$project:{
_id:0
}
}
])

筛选第一篇银行账户文档
db.accounts.aggregate([
{$limit:1}
])

跳过第一篇文档
db.accounts.aggregate([
{$skip:1}
])

db.accounts.update(
{‘name.firstname’:‘alice’},
{$set:
{currency:[“CNY”,“USD”]}
}
)

db.accounts.update(
{“name.firstName”:“bob”},
{$set:
{currency:“GBP”}
}
)

将文档中的货币种类数组展开
db.accounts.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: unwind:{ path:"currency"
}
}
])

展开数组时添加元素位置
db.accounts.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: unwind:{ path:"currency",
includeArrayIndex:“ccyIndex”
}
}
])

db.accounts.insertMany([
{
name:{firstName:“charlie”,lastName:“gordon”},
balance:100
},
{
name:{firstName:“david”,lastName:“wu”},
balance:200,
currency:[]
},
{
name:{firstName:“eddie”,lastName:“kim”},
balance:20,
currency:null
}
])

db.accounts.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: unwind:{ path:'currency’
}
}
])

对银行账户文档进行排序
db.accounts.aggregate([
{
$sort:{
balance:1,
“name.lastName”:-1
}
}
])

db.forex.insertMany([
{
ccy:“USD”,
rate:6.91,
date:new Date(“2018-12-21”)
},
{
ccy:“GBP”,
rate:8.72,
date:new Date(“2018-08-21”)
},
{
ccy:“CNY”,
rate:1.0,
date:new Date(“2018-12-21”)
}
])

将查询到的外汇汇率写入银行账户文档
db.accounts.aggregate([
{
$lookup:{
from : “forex”,
localField:“currency”,
foreignField:“ccy”,
as : “forexData”
}
}
])

如果localField是一个数组字段
db.accounts.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: unwind:{ path:"currency"
}
},
{
$lookup:{
from : “forex”,
localField:“currency”,
foreignField:“ccy”,
as:“forexData”
}
}
])

将特定日期外汇汇率写入文档
db.accounts.aggregate([
{
$lookup:{
from:“forex”,
pipeline:[
{
$match:{
date:new Date(“2018-12-21”)
}
}
],
as:“forexData”
}
}
])

将特定日期外汇汇率写入余额大于100的银行账户文档
db.accounts.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: …ex", let:{bal:"balance"},
pipeline:[
{KaTeX parse error: Expected '}', got 'EOF' at end of input: match: {expr:
{KaTeX parse error: Expected '}', got 'EOF' at end of input: and: [ {eq:[“KaTeX parse error: Expected 'EOF', got '}' at position 30: …("2018-12-21")]}̲ {gt:[”$$bal",100]}
]
}
}
}
],
as:“forexData”
}
}
])

db.transactions.insertMany([
{
symbol:“600519”,
qty:100,
price:567.4,
currency:“CNY”
},
{
symbol:“AMZN”,
qty:1,
price:1377.5,
currency:“USD”
},
{
symbol:“AAPL”,
qty:2,
price:150.7,
currency:“USD”
}
])

按照交易货币来分组交易记录
db.transactions.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{ _id:"currency"
}
}
])

db.transactions.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{ _id:"currency",
totalQty:{ s u m : " sum:" sum:"qty"},
totalNotional:{KaTeX parse error: Expected '}', got 'EOF' at end of input: sum:{multiply:[“ p r i c e " , " price"," price","qty”]}}
}
}
])

使用聚合操作符创建数组字段
db.transactions.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{ _id:"currency",
symbols:{ p u s h : " push:" push:"symbol"}
}
}
])

$out
将聚合管道中的文档写入一个新的集合
db.transactions.aggregate([
{
KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{ _id:"currency",
symbols:{ p u s h : " push:" push:"symbol"}
}
},
{
$out:“output”
}
])

索引:对指定字段进行排序的数据结构

创建索引
db.collection.createIndex()

db.accountsWithIndex.insertMany([
{
name:“alice”,balance:50,currency:[“GBP”,“USD”]
},
{
name:“bob”,balance:20,currency:[“AUD”,“USD”]
},
{
name:“bob”,balance:300,currency:[“CNY”]
}
])

创建一个单键索引
db.accountsWithIndex.createIndex({name:1})

列出集合中已存在的索引
db.accountsWithIndex.getIndexes()

创建一个复合键索引
db.accountsWithIndex.createIndex({name:1,balance:-1})

创建一个多键索引,创建在数组字段上
db.accountsWithIndex.createIndex({currency:1})
数组字段中的每一个元素,都会在多键索引中创建一个键,而每个键都指向所对应的完整的文档的地址

索引的效果
db.collection.explain()

使用没有创建索引的字段进行搜索
db.accountsWithIndex.explain().find({balance:100})

使用以及创建索引的字段进行搜索
db.accountsWithIndex.explain().find({name:‘alice’})

仅返回创建了索引的字段
db.accountsWithIndex.explain().find({name:“alice”},{_id:0,name:1})

使用以及创建索引的字段进行排序
db.accountsWithIndex.explain().find().sort({name:1,balance:-1})

使用为创建索引的字段进行排序
db.accountsWithIndex.explain().find().sort({name:1,balance:1})

使用索引名称删除索引
db.accountsWithIndex.dropIndex(“name_1”)

使用索引定义删除索引
db.accountsWithIndex.dropIndex({name:1,balance:-1})

索引的唯一性
文档主键上创建了默认索引

创建一个具有唯一性的索引
db.accountsWithIndex.createIndex({balance:1},{unique:true})
要使每一篇文档的balance都不同

如果已有文档中的某个字段出现了重复值,就不能在这个字段上创建唯一性索引
例如:
db.accountsWithIndex.createIndex({name:1},{unique:true})

如果新增的文档不包含唯一性索引字段,只有第一篇缺失该字段的文档可以被写入数据库,
索引中该文档的键值被默认为null
db.accountsWithIndex.insert({name:“charlie”,lastAccess:new Date()})

db.accountsWithIndex.dropIndex(“balance_1”)

索引的稀疏性
只将包含索引键字段的文档加入到索引中(及时索引键字段值为null)
db.accountsWithIndex.createIndex({balance:1},{sparse:true})

如果同一个索引既具有唯一性,又具有稀疏性,就可以保存多篇缺失索引键值的文档
db.accountsWithIndex.createIndex({balance:1},{unique:true,sparse:true})

针对日期字段,或者包含日期元素的数组字段,可以使用设定了生存时间的索引,来自动删除字段值超过生存时间的文档

在lastAccess字段上创建一个生存时间是二十秒的索引
db.accountsWithIndex.createIndex({lastAccess:1},{expireAfterSeconds:20})

只有单键索引或者[多键索引包含生存日期]具备生存时间特性
当索引键是包含日期元素的数组字段时,选择最小的日期计算文档是否过期
数据库使用一个后台线程监测和删除过期的文档,删除操作可能有一定的延迟

搭建仓位记录控制服务
搭建一个支持MongoDB数据库CRUD操作的web服务,用来进行交易仓位的管理。
每一条仓位记录包含
交易账号
股票代码
交易数量
交易价格

内嵌结构
规范式结构

文档关系
一对一
使用内嵌结构
一次查询就可以返回所有数据
更具独立性的数据应作为顶层文档
补充性数据应作为内嵌文档
一对多
使用内嵌结构
一次查询就可以返回所有数据
更新内嵌文档的复杂度增高
适合读取频率远高于更新频率的数据
使用规范式结构
减少了重复数据
降低了文档更新的复杂度
需要多次读取操作才能得到完整的数据
使用数组
适合常常需要返回全部相关文档的查询
数组元素较多时,应避免使用内嵌文档

多形性:同一个集合中可以包含不同字段(类型)的文档对象
动态性:线上修改数据模式,应用与数据库都无须下线

恢复数据库
移到有数据的文件夹下
mongorestore

删除数据库
use 数据库
db.dropDatabase()

MongoDB连接字符串
基本格式
mongodb://数据库服务器主机地址:端口号
mongodb://127.0.0.1:27017

from pymongo import MongoClient

if name == ‘main’:
#初始化数据库连接
uri = “mongodb://127.0.0.1:27017”
client = MongoClient(uri)
print(client)

#初始化数据库
#拿到db数据库的句柄
db = client["eshop"]
#拿到集合的句柄
user_coll = db["users"]
#插入一条新的用户数据
new_user = {"username":"nina","password":'xxxx',"email":'1275@qq.com'}
result = user_coll.insert_one(new_user)
print(result)

#更新用户
result = user_coll.update_one({“username”:“nina”},
{"$set":{“phone”:“123456789”}}
)

计算所有订单的总销售额
db.orders.aggregate([
{KaTeX parse error: Expected '}', got 'EOF' at end of input: …d:null, total:{sum:"$total"}
}
}
])

MongpDB启动时将使用一个数据目录存放所有数据文件

模型基础设计
实体
属性
关系

概念模型->逻辑模型->物理模型

文档模型设计时物理模型设计阶段
JSON文档模型通过内嵌数组或者引用字段来表示关系
文档模型设计不遵从第三范式,允许冗余

一对一关系以内嵌文档为主
一对多关系以内嵌数组为主,通过冗余来实现多对多

应用方式
db.contacts.aggregate([
{
$lookup:
{
from : “groups”,
localField:“group_ids”,
foreignField:“group_id”,
as:“groups”
}
}
])

什么时候该用引用方式
内嵌文档太大,数MB或者超过16MB
内嵌文档或数组元素会频繁修改
内嵌数组元素会持续增长,并且没有封顶

MongoDB对使用引用的集合之间并无主外键检查
引用是使用聚合框架的$lookup来模仿关联查询
$lookup只支持left outer join
$lookup的关联目标(from)不能是分片表

分桶设计:
一个文档:一架飞机一个小时的数据

问题:大文档,很多字段,很多索引
列转行

读写分离
向主节点写入一条数据
立即向从节点读取这条数据
保证自己能够读到刚刚写入的数据
db.orders.insert({oid:101,sku:“kiteboar”,q:1},{writeConcern:{w:“majority”}})
db.orders.find({oid:101}).readPref(“secondary”).readConcern(“majority”)

事务的使用
try(ClientSession clientSession =slient.startSession() ){
clientSession.startTransaction();
collection.insertOne(clientSession,docOne);
collection.insertOne(clientSessiion,docTwo);
clientSession.commitTransaction();
}

事务默认在60秒内完成,否则将被取消
Change Stream是MongoDB用于实现变更追踪的解决方案

分片集群解剖:
路由节点mongos
提供集群单一入口
转发应用端请求
选择合适数据节点进行读写
合并多个数据节点的返回
配置节点mongod
提供集群元数据存储,分片数据分布的映射
数据节点mongod
以复制集为单位
横向扩展
最大1024分片
分片之间的数据不重复
所有分片在一起才可以完成完整工作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饼干饼干圆又圆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值