Mongo
MongoDB
启动
mongod启动最少要三个参数
--port 默认27017
--dbpath 默认/data/db
--logpath 默认输出在stdout
启动后用mongo连接服务端 mongo --port=27017, --port是默认参数,可以省略
基本概念
MongoDB是有 Database Collections Documents 结构组成,分别代表 库 表 键值对
Database
-
对于Database 使用
use Database
切换到对应的库中,如果该库不存在,会在这个库存储数据的时候自行创建,所以我们可以直接切换到一个不存在的库中,一个库是对应一个dbpath的
cls mongo清屏show dbs 等同于show databases
use databases 使用库
db 查看当前所在库
db.dropDatebase() 删除当前库 这里的db就是指当前库 -
默认自带三个库
admin root数据库,如果将一个用户添加到这个库,自动继承所有权限
local 这个数据永远不会被复制,用来存储于本地单台服务器的任意集合,这里的复制主要指主从复制机制
config 用于分片设置,在数据库内部使用,用来保存分片的相关信息
Collections
-
对于Collections ,我们在
use Database
切换后 试着给该表创建条数据db.fruit.insert({name:"apple"})
这时候因为存储了新的数据,会自动创建不存在的Database 和 collection
db.fruit.drop() 删除表 -
查看所有集合
show collections | show tables -
创建集合
db.createCollection(集合名,[options])
options可以是如下参数
capped 布尔值 如果为真 创建固定大小集合,达到最大值后悔自动覆盖最早的文档,一般和size,max搭配使用
size 数值 为固定集合指定一个最大值,也就是字节数
max 数值 指定固定集合中包含文档的最大数量
db.createCollection("test",{max:100,capped:True,size:50000})
当集合字节数达到50000或者文档数达到100 就会进行自动覆盖 -
删除集合
db.集合.drop()
基本操作
insert 插入操作 如果不指定_id字段,会自动生成,如果指定了_id就用指定的字段
格式语法1 db.fruit.insertOne({name:"apple"})
新版本的语法insert支持单条也支持多条插入
格式语法2 db.fruit.insertMany([{name:"apple"},{name:"pear"},{name:"banana"}])
insertMany(
[{document1},{document2},{document3}],
{writeConcern: 1,//写入策略,默认1,要求确认写操作, 0 是不要求,
ordered: true, //指定是否按顺序写入默认是真,按顺序写入,
}
)
还可以用js的for循环进行插入
```
> for (i=0;i<10;i++){
... db.test.insert({name:"aa"+i,index:i})
... }
WriteResult({ "nInserted" : 1 }) #因为是循环 每次插入只有一条,因此显示插入条数始终是1条
```
find 查询操作
db.fruit.find({""})
db.test.find({age:18}) 单条件查询
db.test.find({age:18,city:"shanghai"}) 多条件查询语法1
db.test.find({$and:[{age:18},{city:"shanghai"}]}) 多条件查询语法2
db.test.find({$and:[{age:18},{age:19}]}) 这种多条件要注意,同样的文档字段在多条件查询中,后面的会覆盖前面的
db.test.find({$or:[{age:18},{city:"shanghai"}]}) 多条件查询语法2 或条件
db.test.find({"age":{$lt:50}}) 等同于where age < 50
db.test.find({"age":{$lte:50}}) 等同于where age <= 50
db.test.find({"age":{$ne:50}}) 等同于where age != 50
db.test.find({"age":{$gt:50},$or:[{name:"大娃"},{name:"二娃"}]}) 匹配age大于50,并且name是大娃或者二娃的结果
对于子文档的查询 db.test.insertOne({name:"apple",from:{country:"usa",province:"los angle"}})
比如插入一条嵌套的子文档,那么查询方式是db.test.find({"from.country":"usa"})
模糊匹配只能用正则实现
db.test.find({"city":/^shan/,name:"大娃"}) //按正则语法查询 /^shan/ shan开头的 /我/ 匹配带有"我"的文档
分页 将返回值按照每页n条数据显示,这里需要skip()和limit() skip是显示第N页 索引默认从0开始,limit限制每页显示的个数
db.test.find({name:/^aa/}).sort({index:-1}).skip(1).limit(4)
显示第二页4个数据
排序
db.test.find({name:/^aa/}).sort({index:-1})
对返回值按照index进行排序 -1是降序 1 是升序
db.test.find({name:/^aa/}).sort({index:-1,name:1})
index降序 同时name升序排列
汇总数count()
db.集合.count() 或者 db.集合.find().count()
去重distinct()
db.集合.find("字段").distinct()
对数组的查询
db.test.insert([{name:"apple",color:["red","yellow"]},{name:"mongo",color:["blue","black"]},])
db.test.find({color:"red"})和db.test.find({$or:[{color:"red"},{color:"blue"}]})会产生不同的结果,
前者返回color含有red的记录,只会返回一条数据,而后者返回的是color含有red或者blue的记录,2条都会返回
---------------------------------------------------------------------------------------------
比如插入的数据为
db.test.insertOne({
title:"title1",
location:[{"city":"los angles","state":"ca","country":"usa"},
{"city":"ningbo","state":"zhejiang","country":"china"},
{"city":"rome","state":"lazio","country":"italy"},
]
})
我们对location的元素要多个匹配的时候可以用
db.test.find({"location.city":"ningbo","location.city":"rome"})
或者用$elemMatch参数 这2中都是对子对象中满足多个字段条件时候使用
db.test.find({"location":{$elemMatch:{"country":"china","city":"ningbo"}}})
他们的返回值会是如下
{ "_id" : ObjectId("62a750fa76a416fb3c2c4bc1"), "title" : "title1", "location" : [ { "city" : "los angles", "state" : "ca", "country" : "usa" }, { "city" : "ningbo", "state" : "zhejiang", "country" : "china" }, { "city" : "rome", "state" : "lazio", "country" : "italy" } ] }
按照数组的长度查询 用$size拼接符 比如对下面插入的内容查找color数组为2个的 db.test.find({color:{$size:2}})
db.test.insert([{name:"apple",color:["red","yellow"]},{name:"mongo",color:["blue","black"]},])
投影机制,我们对返回值的字段也可以设置是否需要,拿上面的例子db.test.find({"location":{$elemMatch:{"country":"china","city":"ningbo"}}})
我们改成db.test.find({ "location":{$elemMatch:{"country":"china","city":"ningbo"}} },{"_id":0,"location":1})
他就只返回location字段,_id因为设置为0不会返回,titile没有提及,也不会返回
remove命令 删除文档
语法:
db.集合.remove(
query, 删除条件
{
justOne: boolean 为真只删除一个文档
writeConcern: document 抛出异常的级别
}
)
示例
db.test.remove({aa:"aa"},{justOne:"True"}) 所有匹配的记录只会删除一条
db.test.remove({a:1}) 删除a为1的记录
db.test.remove({a:{$lt:5}}) 删除a小于5的记录
db.test.remove({}) 删除所有记录
db.test.remove({_id:ObjectId("62a82a137e7718372c570cfc")}) 对于自动生成的_id 要把objectid函数写上,但是如果是自己手动创建的_id字段就不用
update命令 更新文档
语法
db.集合.update(
query, 查询条件
update, 更新的对象
{
upsert:boolean, 如果为真,不存在是则插入,默认为真
multi:boolean 默认false只更新第一条记录,true则更新全部记录
writeConcern:document 抛出异常的级别
}
)
update 默认会将找到的记录删除,然后插入一条新的.假如有条记录为{age:15},{name:"aaa"},我们db.test.update({age:15},{age:28})
这条记录的name:aaa也会消失不见.
要是只想更新某个字段,其他字段保持不变,需要下面的$set 拼接符
db.test.updateOne({name:"apple"},{$set:{from:"china"}})
比如这条会找到name为apple的记录,新增一个键from,如果from这个键没有,则新增后面的值,如果有则更新后面的值
updateOne 无论匹配到多少条记录,永远只更新第一条; updateMany 匹配多少条就更新多少条
updateOne / updateMany 更新条件部分必须要有如下参数
- $set/$unset
- $push/$pushAll/$pop
- $pull/$pullAll
- $addToSet
drop 删除集合(表)
db.集合.drop() 表会被删除,全部文档和索引都会被删除
db.dropDatabase() 这个语句在use database语句后执行,删除的就是当前的库
-
逻辑符
$type的应用
$type代表了各种数据类型的连接符,可以用$type查特定的文档类型.
类型 | 数字 | 备注 |
---|---|---|
Double | 1 | |
String | 2 | |
Object | 3 | |
Array | 4 | |
Binary data | 5 | |
Undefined | 6 | 已废弃。 |
Object id | 7 | |
Boolean | 8 | |
Date | 9 | |
Null | 10 | |
Regular Expression | 11 | |
JavaScript | 13 | |
Symbol | 14 | |
JavaScript (with scope) | 15 | |
32-bit integer | 16 | |
Timestamp | 17 | |
64-bit integer | 18 | |
Min key | 255 | Query with -1 . |
Max key | 127 | |
db.test.find({age:{$type:2}}) 或者 db.test.find({age:{$type:"String"}}) 查所有age字段 值是字符串类型的结果 在数据库中所有的数字默认都是double类型 |
索引
创建索引
- Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可
db.collection.createIndex(keys, options)
db.col.createIndex({"title":1}
createIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)
db.col.createIndex({"title":1,"description":-1})
会以title字段升序创建索引,如果titile字段相同时以description字段降序创建索引 代码示例
db.test.createIndex({"name":1},{name:"index_name",expireAfterSeconds:10})
- options可选参数详情如下
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
dropDups | Boolean | 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false. |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. 有些字段为空值,对这些空值的字段不创建索引 |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v | index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language. |
查看集合索引
db.col.getIndexes()
查看集合索引大小
db.col.totalIndexSize()
索引删除
db.col.dropIndexes()
删除集合指定索引
db.col.dropIndex("索引名称")
删除指定索引
复合索引
一个索引由多个key进行维护的索引 称为复合索引 db.test.createIndex({name:1,age:-1})
关系型数据库的复合索引采取的是左包含原则, 比如id是自增索引,后续增加了name age字段作为复合索引.
那么查询的时候id name age 或者id name 或者id age 这样的查询方式是可以有效利用索引机制,提高查询速度的.但是如果查询顺序为age name id的话 就利用不了索引机制了
mongodb 和关系型数据库也差不多,只是有点不同,只要符合左包含原则的前提下,顺序调换一下也可以,mongo内部会根据字段顺序自动调整.所以mongdb只要查询字段有id字段
官方文档 https://www.mongodb.com/docs/v5.0/core/multikey-index-bounds/
聚合查询
Mongo自带的聚合参数
常见步骤的运算符
$match
$eq / $gt / $gte / $tt / $lte $andl $orl $not / $in $geowithin / $intersect
$project
1. 选择需要的或排除不需要的字段
2. $map / $reduce / $fiter $range $muttiply / $divide / $substract / $add
3. $year / $month / $dayofMonth / $hour / $minute / $second等等
$group
$sum / $avg
$push / $addToset
$ first / $last / $max / $min
$unwind 用来展开数组
$graphLookup 图搜索
$facet/$bucket 分面搜索
aggregate() 方法
语法: db.集合.aggregate(AGGREGATE_OPERATION)
以一个$sum求和为例,插入的文档如下
db.test2.insert([
{
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
}
])
求和的语法为 db.test2.aggregate([{$group:{_id:"$by_user",sum_by_user:{$sum:"$likes"}}}])
对语法详解
db.test2.aggregate(
#聚合函数后要一个数组类型
[
# $group 后面{_id:"$by_user"} 表示以by_user字段进行分组, _id和文档里的_id不是一个事,不要搞混
# sum_by_user 是一个自定义的字段,用来展示聚合分组后的字段
# {$sum:"$likes"} 代表对likes字段进行求和
{$group:{_id:"$by_user",sum_by_user:{$sum:"$likes"}}}
]
)
常见表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 将值加入一个数组中,但不会对数组中重复数据去重。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 将值加入一个数组中,会对数组重复数据进行去重。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
搭建副本集
https://www.cnblogs.com/boshen-hzb/p/10419760.html
-
创建数据目录
mkdir -p /repl/data1 mkdir -p /repl/data2 mkdir -p /repl/data3
-
搭建副本集
mongod --prot 27017 --dbpath /repl/data1 --bind_ip 0.0.0.0 --replset myreplace/localhost:27018,localhost:27019 mongod --prot 27018 --dbpath /repl/data2 --bind_ip 0.0.0.0 --replset myreplace/localhost:27017,localhost:27019 mongod --prot 27019 --dbpath /repl/data3 --bind_ip 0.0.0.0 --replset myreplace/localhost:27018,localhost:27017
--replset 副本集 myreplace是副本集的自定义名称 后面是副本集其他节点的主机ip和端口
-
配置副本集,连接任意节点 这里进入mongo界面设置
-
use admin
-
初始化副本集
var config = { _id:"myreplace", members:[ {_id:0,host:"localhost:27017"}, {_id:1,host:"localhost:27018"}, {_id:2,host:"localhost:27019"}, ] }
-
初始化配置
rs.initiate(config)
-
设置客户端临时访问
rs.slaveok()
-