CentOS7下MongoDB的安装和使用

目录

 

背景

安装

客户端命令

数据库命令

集合命令

数据类型及数据操作

数据类型

数据操作

删除某个集合的记录

扫描二维码关注公众号,回复: 12930984 查看本文章

数据库备份

数据库恢复

聚合

分组$group

投影$project

过滤$match

索引

建立索引

删除索引

创建唯一索引

建立复合索引

结语

背景

总结下初夏学习MongoDB的笔记,这是一个可以存储大数据量的NoSQL数据库,支持分布式,存储基本格式就是json键值对

安装

1、修改yum文件,添加源
[root@localhost szc]# vim /etc/yum.repos.d/mongodb-org-3.4.repo

内容如下

name=MongoDB Repository  
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/  
gpgcheck=0  
enabled=1  
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc

2、安装之,下载慢的话,一次不行多试几次

[root@localhost szc]# yum -y install mongodb-org

3、完成后,查看位置

[root@localhost szc]# whereis mongod
mongod: /usr/bin/mongod /etc/mongod.conf /usr/share/man/man1/mongod.1

4、修改/etc/mongod.conf配置文件,注释掉bindip以允许远程访问

[root@localhost szc]# vim /etc/mongod.conf
[root@localhost szc]# cat /etc/mongod.conf
# mongod.conf


# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/


# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log # 日志文件路径


# Where and how to store data.
storage:
  dbPath: /var/lib/mongo # 数据文件目录
  journal:
    enabled: true
#  engine:
#  mmapv1:
#  wiredTiger:

# how the process runs
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /var/run/mongodb/mongod.pid  # location of pidfile


# network interfaces
net:
  port: 27017
  #bindIp: 127.0.0.1  # Listen to local interface only, comment to listen on all interfaces.

5、启动mongodb服务端,并设置开机启动

[root@localhost szc]# systemctl start mongod.service
[root@localhost szc]# systemctl enable mongod.service

6、关闭mongodb服务端

systemctl stop mongod.service

7、启动客户端

[root@localhost szc]# mongo

客户端命令

数据库命令

 
显示所有数据库
> show dbs

admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB

使用某个数据库(不需要创建)

> use test

switched to db test

新创建的数据库必须要往里面插入数据后才能在show dbs里显示(假设新建了个test2数据库)

> db.createCollection("user")
{ "ok" : 1 }

> show dbs
admin  0.000GB
local  0.000GB
test2  0.000GB

删除当前数据库

> db.dropDatabase()
{ "ok" : 1 }

集合命令

 
显示当前数据库下所有的集合(表)
> show collections

student
user

创建集合

> db.createCollection("article_url")

{ "ok" : 1 }

可选参数,capped表示固定集合容量,size指定容量(单位为字节)

> db.createCollection("user", {capped:true, size:10})
{ "ok" : 1 }

删除集合

> db.user.drop()
true

数据类型及数据操作

数据类型

ObjectID:12字节的文档id,用于保证文档的唯一性。12个字节组成:4个字节的时间戳+3个字节的机器id+2个字节的mongodb服务进程id+3个字节的增量值。
 

String:utf-8字符串

Integer:32位或64位整数

Double:浮点数
 
Arrays:数组或列表,多个值映射到一个键
 
Object:对象,用于嵌入式的文档,也就是一个值就是一个文档
 
Null:空值
 
Timestamp:时间戳,从1970年月1日到现在的秒数
 
Date:当前日期的unix时间格式
> new Date("2020-06-15")
ISODate("2020-06-15T00:00:00Z")

不传参就是现在的格里尼治时间

> new Date()
ISODate("2020-06-15T03:35:32.016Z")

数据操作

1、插入数据:
我们先给集合test2(不存在就自动创建)插入一条数据,再查看数据,就可以看到ObjectId,对应键为_id,这是一条记录的主键
> db.test2.insert({"name":"szc", "age":23})
WriteResult({ "nInserted" : 1 })

> db.test2.find()
{ "_id" : ObjectId("5ee6ed5e757d5ca426d608b4"), "name" : "szc", "age" : 23 }

再插入一条,可以看到ObjectId加了个1

> db.test2.insert({"name":"jason", "age":22})
WriteResult({ "nInserted" : 1 })

> db.test2.find()
{ "_id" : ObjectId("5ee6ed5e757d5ca426d608b4"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 22 }

插入数据时要保证_id唯一,但保存数据时就可以进行旧数据覆盖

> db.test2.insert({"_id":1, "name":"a", "age": 11})
WriteResult({ "nInserted" : 1 })

> db.test2.find()
{ "_id" : ObjectId("5ee6ed5e757d5ca426d608b4"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 22 }
{ "_id" : 1, "name" : "a", "age" : 11 }

> db.test2.save({"_id":1, "name":"a", "age": 12})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.test2.find()
{ "_id" : ObjectId("5ee6ed5e757d5ca426d608b4"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 22 }
{ "_id" : 1, "name" : "a", "age" : 12 }

2、更新数据:

把匹配的记录更新为指定的记录
> db.test2.update({"name":"a"}, {"name":"b"})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.test2.find()
{ "_id" : ObjectId("5ee6ed5e757d5ca426d608b4"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 22 }
{ "_id" : 1, "name" : "b" }

可见{ "_id" : 1, "name" : "a", "age" : 12 }这条数据被覆盖成了{ "_id" : 1, "name" : "b" }, age字段没了

如果要更新某个字段,就要使用$set
> db.test2.update({"name":"jason"}, {$set:{"age":21}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.test2.find()
{ "_id" : ObjectId("5ee6ed5e757d5ca426d608b4"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : 1, "name" : "b" }

默认更改一条数据,如果要更改多个,就加上multi:true

> db.test2.update({"name":"szc"}, {$set:{"name":"songzeceng"}}, {multi:true})
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })

> db.test2.find()
{ "_id" : ObjectId("5ee6ed5e757d5ca426d608b4"), "name" : "songzeceng", "age" : 23 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : 1, "name" : "b" }
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }

而multi只能和$配合工作

 
3、删除数据
使用justOne删除最老的一条数据
> db.test2.remove({"name":"songzeceng"}, {justOne:true})
WriteResult({ "nRemoved" : 1 })

> db.test2.find()
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : 1, "name" : "b" }
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }

不加justOne,就会删除所有匹配的数据

 
4、查询数据
4.1、查询匹配的一条数据
> db.test2.findOne({"age":17})
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }

4.2、运算符,查询age字段≤30的所有记录

> db.test2.find({"age":{$lte:30}})
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }

lte:≤,lt:<,gt:>,gte:≥,ne:≠

4.3、范围运算符
> db.test2.find({"age":{$in:[17, 21, 25]}})
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }

4.4、逻辑运算

1)、逻辑与:直接加一个字段即可

> db.test2.find({"age":{$in:[17, 21, 25]}, "name":"jason"})
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }

2)、逻辑或:$or

> db.test2.find({$or:[{"age":{$in:[17, 21, 25]}}, {"name":"szc"}]})
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }

4.5、正则表达式

查询以s开头的数据

> db.test2.find({"name":/^s/})
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc", "age" : 23 }

查询以ng结尾的数据

> db.test2.find({"name":/ng$/})
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }

也可以把//换成$regex

> db.test2.find({"name":{$regex:"ng$"}})
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }

4.6、查询前两个

> db.test2.find().limit(2)
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : 1, "name" : "b" }

4.7、跳过前两个

> db.test2.find().skip(2)
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }

两者可以配合使用来实现翻页,而此时skip和limit的顺序是无所谓的,都是先跳过,再限制

> db.test2.find().limit(2).skip(1)
{ "_id" : 1, "name" : "b" }
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }

> db.test2.find().skip(1).limit(2)
{ "_id" : 1, "name" : "b" }
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }

4.8、自定义查询,使用$where定义函数

> db.test2.find({$where:function(){return this.age <= 25}})
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }

过滤要返回的字段,1表示返回,0和不写表示不返回

> db.test2.find({$where:function(){return this.age <= 25}}, {name:1, _id:0})
{ "name" : "jason" }
{ "name" : "songzeceng" }
{ "name" : "szc" }
{ "name" : "bob" }

但_id不写却也是返回的

> db.test2.find({$where:function(){return this.age <= 25}}, {name:1})
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason" }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng" }
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc" }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob" }

输出所有文档,并对字段进行映射

> db.test2.find({}, {_id:0, name:1})
{ "name" : "jason" }
{ "name" : "b" }
{ "name" : "songzeceng" }
{ "name" : "songzeceng" }
{ "name" : "szc" }
{ "name" : "bob" }

5、排序,使用sort函数,1表示升序,-1表示降序

> db.test2.find().sort({age:1})
{ "_id" : 1, "name" : "b" }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }

当排序字段是非数值型时,就按照字母序进行排序

> db.test2.find().sort({name:-1})
{ "_id" : ObjectId("5ee6f279757d5ca426d608b8"), "name" : "szc", "age" : 23 }
{ "_id" : ObjectId("5ee6f05d757d5ca426d608b6"), "name" : "songzeceng", "age" : 32 }
{ "_id" : ObjectId("5ee6f062757d5ca426d608b7"), "name" : "songzeceng", "age" : 24 }
{ "_id" : ObjectId("5ee6edac757d5ca426d608b5"), "name" : "jason", "age" : 21 }
{ "_id" : ObjectId("5ee6f285757d5ca426d608b9"), "name" : "bob", "age" : 17 }
{ "_id" : 1, "name" : "b" }

6、统计,使用count()函数

> db.test2.find({age:{$gte:18}}).count()
4

也可以只用count()函数,把条件写在count()函数里

> db.test2.count({age:{$lte:25}})
4

7、查看所有不重复的字段值

> db.test2.distinct("name")
[ "jason", "b", "songzeceng", "szc", "bob" ]

也可以添加条件

> db.test2.distinct("name", {"age":{$lt:20}})
[ "bob" ]

删除某个集合的记录

> db.article_url.remove({});
WriteResult({ "nRemoved" : 30 })

数据库备份

给出服务器地址、数据库名和导出路径

[root@localhost szc]# mongodump -h 192.168.57.141 -d test2 -o /home/szc/monogo
2020-06-15T13:00:15.083+0800    writing test2.test2 to
2020-06-15T13:00:15.084+0800    writing test2.t0 to
2020-06-15T13:00:15.085+0800    done dumping test2.test2 (6 documents)
2020-06-15T13:00:15.085+0800    done dumping test2.t0 (0 documents)

[root@localhost szc]# ll /home/szc/monogo/
total 0
drwxr-xr-x. 2 root root 90 Jun 15 13:00 test2

[root@localhost szc]# ll /home/szc/monogo/test2
total 12
-rw-r--r--. 1 root root   0 Jun 15 13:00 t0.bson
-rw-r--r--. 1 root root  80 Jun 15 13:00 t0.metadata.json
-rw-r--r--. 1 root root 291 Jun 15 13:00 test2.bson
-rw-r--r--. 1 root root  83 Jun 15 13:00 test2.metadata.json
[root@localhost szc]#

数据库恢复

给出服务器地址、导入的数据库名和导入路径

[root@localhost szc]# mongorestore -h 192.168.57.141 -d restore2 --dir /home/szc/monogo/test2

聚合

聚合是基于数据处理的聚合管道,每个文档通过一个由多阶段组成的管道,可以对每个阶段的管道进行分组、过滤等操作,然后经过一系列处理,输出相应结果。
常用管道有$group、$match、$project等

分组$group

> db.test2.aggregate({$group: {_id:"$name"}})
{ "_id" : "bob" }
{ "_id" : "jason" }
{ "_id" : "szc" }
{ "_id" : "b" }
{ "_id" : "songzeceng" }

分组并统计,使用$sum操作符,1表示将第一列(_id)进行累加

> db.test2.aggregate({$group: {_id:"$name", count:{$sum: 1}}})
{ "_id" : "bob", "count" : 1 }
{ "_id" : "jason", "count" : 1 }
{ "_id" : "szc", "count" : 1 }
{ "_id" : "b", "count" : 1 }
{ "_id" : "songzeceng", "count" : 2 }

对age取均值

> db.test2.aggregate({$group: {_id:"$name", count:{$sum: 1}, avg: {$avg: "$age"}}})
{ "_id" : "bob", "count" : 1, "avg" : 17 }
{ "_id" : "jason", "count" : 1, "avg" : 21 }
{ "_id" : "szc", "count" : 1, "avg" : 23 }
{ "_id" : "b", "count" : 1, "avg" : null }
{ "_id" : "songzeceng", "count" : 2, "avg" : 28 }

group by null,用于对把所有文档分成一组

> db.test2.aggregate({$group: {_id:null, sum:{$sum: 1}, mean_age:{$avg:"$age"}}})
{ "_id" : null, "sum" : 6, "mean_age" : 23.4 }

按多个字段分组

> db.test2.aggregate({$group:{_id:{name:"$name",age:"$age"}, count:{$sum:1}, avg:{$avg:"$age"}}})
{ "_id" : { "name" : "bob", "age" : 17 }, "count" : 1, "avg" : 17 }
{ "_id" : { "name" : "szc", "age" : 23 }, "count" : 1, "avg" : 23 }
{ "_id" : { "name" : "b" }, "count" : 1, "avg" : null }
{ "_id" : { "name" : "songzeceng", "age" : 24 }, "count" : 1, "avg" : 24 }
{ "_id" : { "name" : "jason", "age" : 21 }, "count" : 1, "avg" : 21 }
{ "_id" : { "name" : "songzeceng", "age" : 32 }, "count" : 1, "avg" : 32 }

使用多个分组管道时,可以取前一个管道中字段里的值作为键

> db.test2.aggregate({$group:{_id:{name:"$name",age:"$age"}, count:{$sum:1}, avg:{$avg:"$age"}}}, {$group:{_id:"$_id.name", count:{$sum:1}}})
{ "_id" : "jason", "count" : 1 }
{ "_id" : "bob", "count" : 1 }
{ "_id" : "szc", "count" : 1 }
{ "_id" : "b", "count" : 1 }
{ "_id" : "songzeceng", "count" : 2 }

投影$project

可以改变输出的字段

> db.test2.aggregate({$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$project:{name:"$_id", count:"$count", avg:"$avg"}})
{ "_id" : "bob", "name" : "bob", "count" : 1, "avg" : 17 }
{ "_id" : "jason", "name" : "jason", "count" : 1, "avg" : 21 }
{ "_id" : "szc", "name" : "szc", "count" : 1, "avg" : 23 }
{ "_id" : "b", "name" : "b", "count" : 1, "avg" : null }
{ "_id" : "songzeceng", "name" : "songzeceng", "count" : 2, "avg" : 28 }

也可以控制字段输出与否

> db.test2.aggregate({$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$project:{name:"$_id", count:1, avg:1, _id:0}})
{ "count" : 1, "avg" : 17, "name" : "bob" }
{ "count" : 1, "avg" : 21, "name" : "jason" }
{ "count" : 1, "avg" : 23, "name" : "szc" }
{ "count" : 1, "avg" : null, "name" : "b" }
{ "count" : 2, "avg" : 28, "name" : "songzeceng" }

过滤$match

比如选择年龄>=20的记录

> db.test2.aggregate({$match:{age:{$gte:20}}}, {$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$project:{name:"$_id", count:1, avg:1, _id:0}})
{ "count" : 2, "avg" : 28, "name" : "songzeceng" }
{ "count" : 1, "avg" : 23, "name" : "szc" }
{ "count" : 1, "avg" : 21, "name" : "jason" }

$match里也可以使用$or等逻辑操作符

> db.test2.aggregate({$match:{$or:[{age:{$gte:20}}, {name:{$regex:"^b"}}]}}, {$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$project:{name:"$_id", count:1, avg:1, _id:0}})
{ "count" : 1, "avg" : 17, "name" : "bob" }
{ "count" : 1, "avg" : 21, "name" : "jason" }
{ "count" : 1, "avg" : 23, "name" : "szc" }
{ "count" : 1, "avg" : null, "name" : "b" }
{ "count" : 2, "avg" : 28, "name" : "songzeceng" }

排序$sort,-1表示降序,1表示升序

> db.test2.aggregate({$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$sort:{avg: -1}})
{ "_id" : "songzeceng", "count" : 2, "avg" : 28 }
{ "_id" : "szc", "count" : 1, "avg" : 23 }
{ "_id" : "jason", "count" : 1, "avg" : 21 }
{ "_id" : "bob", "count" : 1, "avg" : 17 }
{ "_id" : "b", "count" : 1, "avg" : null }

取有限值$limit与跳过$skip,和find()查询里用法类似

> db.test2.aggregate({$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$sort:{avg: -1}}, {$limit:2})
{ "_id" : "songzeceng", "count" : 2, "avg" : 28 }
{ "_id" : "szc", "count" : 1, "avg" : 23 }

> db.test2.aggregate({$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$sort:{avg: -1}}, {$skip:2})
{ "_id" : "jason", "count" : 1, "avg" : 21 }
{ "_id" : "bob", "count" : 1, "avg" : 17 }
{ "_id" : "b", "count" : 1, "avg" : null }

两者依旧可以组合使用,但此时顺序的先后就有区别了,注意find()查询中两者的顺序是无所谓的

> db.test2.aggregate({$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$sort:{avg: -1}}, {$skip:2}, {$limit:1})
{ "_id" : "jason", "count" : 1, "avg" : 21 }

> db.test2.aggregate({$group:{_id:"$name", count:{$sum:1}, avg:{$avg:"$age"}}}, {$sort:{avg: -1}}, {$limit:1}, {$skip:2})
>

展开$unwind

> db.test2.insert({"name":"songzeceng", "langs":["Java", "C", "C++", "Python", "Scala"]})
WriteResult({ "nInserted" : 1 })

> db.test2.aggregate({$match:{name:"songzeceng"}}, {$unwind:"$langs"})
{ "_id" : ObjectId("5ee73ef68ea0bda5c6c60db1"), "name" : "songzeceng", "langs" : "Java" }
{ "_id" : ObjectId("5ee73ef68ea0bda5c6c60db1"), "name" : "songzeceng", "langs" : "C" }
{ "_id" : ObjectId("5ee73ef68ea0bda5c6c60db1"), "name" : "songzeceng", "langs" : "C++" }
{ "_id" : ObjectId("5ee73ef68ea0bda5c6c60db1"), "name" : "songzeceng", "langs" : "Python" }
{ "_id" : ObjectId("5ee73ef68ea0bda5c6c60db1"), "name" : "songzeceng", "langs" : "Scala" }

展开后统计

> db.test2.aggregate({$match:{name:"songzeceng"}}, {$unwind:"$langs"}, {$group:{_id:null, total:{$sum:1}}}, {$project:{_id:0, total:1}})
{ "total" : 5 }

$unwind会默认过滤掉那些展开字段缺失的记录,可以指定preserveNullAndEmptyArrays:true来取消过滤

> db.test2.aggregate({$unwind:{path:"$langs", preserveNullAndEmptyArrays:true}}, {$project:{_id:0, name:1, langs:1}})
{ "name" : "jason" }
{ "name" : "b" }
{ "name" : "songzeceng" }
{ "name" : "songzeceng" }
{ "name" : "szc" }
{ "name" : "bob" }
{ "name" : "songzeceng", "langs" : "Java" }
{ "name" : "songzeceng", "langs" : "C" }
{ "name" : "songzeceng", "langs" : "C++" }
{ "name" : "songzeceng", "langs" : "Python" }
{ "name" : "songzeceng", "langs" : "Scala" }

索引

建立索引

先插入10万条数据
> for(i=0;i<100000;i++) {db.test3.insert({name:'test'+i, age:i})}
WriteResult({ "nInserted" : 1 })

然后查询某一数据,并显示执行时间。结果中的executionTimeMillis表示执行时间,单位毫秒

> db.test3.find({'name':'test2341'}).explain("executionStats")
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test2.test3",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "name" : {
                "$eq" : "test2341"
            }
        },
        "winningPlan" : {
            "stage" : "COLLSCAN",
            "filter" : {
                "name" : {
                    "$eq" : "test2341"
                }
            },
            "direction" : "forward"
        },
        "rejectedPlans" : [ ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1,
        "executionTimeMillis" : 26,
        "totalKeysExamined" : 0,
        "totalDocsExamined" : 100000,
        "executionStages" : {
            "stage" : "COLLSCAN",
            "filter" : {
                "name" : {
                    "$eq" : "test2341"
                }
            },
            "nReturned" : 1,
            "executionTimeMillisEstimate" : 10,
            "works" : 100002,
            "advanced" : 1,
            "needTime" : 100000,
            "needYield" : 0,
            "saveState" : 781,
            "restoreState" : 781,
            "isEOF" : 1,
            "invalidates" : 0,
            "direction" : "forward",
            "docsExamined" : 100000
        }
    },
    "serverInfo" : {
        "host" : "localhost.localdomain",
        "port" : 27017,
        "version" : "3.4.24",
        "gitVersion" : "865b4f6a96d0f5425e39a18337105f33e8db504d"
    },
    "ok" : 1
}

建立索引,1表示按name升序(这里升序降序区别不大)

> db.test3.ensureIndex({name:1})
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

再看看执行时间

> db.test3.find({'name':'test2341'}).explain("executionStats")
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test2.test3",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "name" : {
                "$eq" : "test2341"
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "name" : 1
                },
                "indexName" : "name_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "name" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "name" : [
                        "[\"test2341\", \"test2341\"]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1,
        "executionTimeMillis" : 0,
        "totalKeysExamined" : 1,
        "totalDocsExamined" : 1,
        "executionStages" : {
            "stage" : "FETCH",
            "nReturned" : 1,
            "executionTimeMillisEstimate" : 0,
            "works" : 2,
            "advanced" : 1,
            "needTime" : 0,
            "needYield" : 0,
            "saveState" : 0,
            "restoreState" : 0,
            "isEOF" : 1,
            "invalidates" : 0,
            "docsExamined" : 1,
            "alreadyHasObj" : 0,
            "inputStage" : {
                "stage" : "IXSCAN",
                "nReturned" : 1,
                "executionTimeMillisEstimate" : 0,
                "works" : 2,
                "advanced" : 1,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "keyPattern" : {
                    "name" : 1
                },
                "indexName" : "name_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "name" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "name" : [
                        "[\"test2341\", \"test2341\"]"
                    ]
                },
                "keysExamined" : 1,
                "seeks" : 1,
                "dupsTested" : 0,
                "dupsDropped" : 0,
                "seenInvalidated" : 0
            }
        }
    },
    "serverInfo" : {
        "host" : "localhost.localdomain",
        "port" : 27017,
        "version" : "3.4.24",
        "gitVersion" : "865b4f6a96d0f5425e39a18337105f33e8db504d"
    },
    "ok" : 1
}

从26毫秒到0毫秒,效果还是很显著的

获取所有索引
> db.test3.getIndexes()
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "test2.test3"
    },
    {
        "v" : 2,
        "key" : {
            "name" : 1
        },
        "name" : "name_1",
        "ns" : "test2.test3"
    }
]

删除索引

> db.test3.dropIndex({name:1})
{ "nIndexesWas" : 2, "ok" : 1 }

创建唯一索引

创建后,再插入数据时就进行数据去重,新数据不会覆盖老数据,直接报错

> db.test3.ensureIndex({"name":1}, {"unique":true})
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

建立复合索引

> db.test3.ensureIndex({"name":1, "age":-1})
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

> db.test3.getIndexes()
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "test2.test3"
    },
    {
        "v" : 2,
        "key" : {
            "name" : 1,
            "age" : -1
        },
        "name" : "name_1_age_-1",
        "ns" : "test2.test3"
    }
]

结语

以上就是MongoDB的学习笔记,谢谢阅读

猜你喜欢

转载自blog.csdn.net/qq_37475168/article/details/108463888