MongoDB扫盲-黑马

MongoDB从入门到入土

1、MongoDB相关的概念

1.1MongoDB适用的场景

1、数据量大

2、写入操作频繁

3、价值较低的数据,对事务性要求不高

1.2MongoDB简介

MongoDB是一个开源、高性能、无模式的文档型数据库,是NoSQL数据库产品中的一种,是最像关系型数据库的非关系型数据库。

无模式:指MongoDB没有一个具体的列,他存储用的是类似于JSON的格式叫BSON,一种二进制的JSON文件

MongoDB中的记录是一个文档,他是一个由字段和值对(field:value)组成的数据结构。MongoDB文档类似于JSON对象即认为一个文档是一个对象。字段的数据类型是字符型,他的值除了使用基本的一些类型外,还可以包括其他文档、普通数组和文档数组。

1.3MongoDB体系结构

MongoDB扫盲-黑马_第1张图片

  • MongoDB自动将_id字段设置为主键

1.4MongoDB的特点

1、高性能

2、高可用性

MongoDB的复制工具称为副本集(replica set),他可以提供自动故障转移和数据冗余

3、高扩展性

分片将数据分布在一组集群的机器上,支持海量数据存储,服务能力水平扩展

4、丰富的查询支持

MongoDB支持丰富的查询语言,支持读写操作,比如数据聚合,MongoDB将一个区域所覆盖的读写只定向到该区域内的那些片

2、单机部署

2.1安装

百度云:https://pan.baidu.com/s/18au42FIhSNrXY9p7MbmNbg 提取码:29ad

解压即可使用

2.2启动

命令行方式:

在bin目录下创建data文件夹,在data文件夹下创建db文件夹,打开cmd命令行,执行下面命令:

mongod --dbpath=..\data\db

MongoDB扫盲-黑马_第2张图片
配置文件方式:

在bin目录下创建conf文件夹,在conf文件夹下创建mongod.conf文件,增加下面的配置:

storage: 
    #The directory where the mongod instance stores its data.Default Value is "\data\db" on Windows. 
    dbPath: E:\\MongoDB\\mongodb-win32-x86_64-2008plus-ssl-4.0.12\\data\\db

打开cmd命令行,执行下面命令:

mongod -f ..\conf\mongod.conf

2.3图形化客户端

compass、navicat

3、基本常用命令

3.1数据库操作

# 查看数据库
> show dbs

# 创建并使用数据库,此时这个库还只是在内存中,只有添加了集合之后才持久化到磁盘,使用show dbs命令才可以看得到
> use articledb

# 查看正在使用的数据库
> db

# 删除数据库,主要用来删除已经持久化的数据库
> db.dropDatabase()

有一些数据库是保留的,具有特定的作用:

  • admin:与权限有关的数据库,要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这库运行,比如列出所有的数据库或者关闭服务器。
  • local:这个数据永远不被复制,可以用来存储限于本地单台服务器的任意集合
  • config:当MongoDB分片时,config数据库在内部使用,用于保存分片信息

3.2集合的操作

当向一个集合中插入一个文档的时候,如果集合不存在,则会自动创建集合,这种方式称为隐式创建,当然你也可以显式创建。

显式创建命令:

# 创建一个集合
> db.createCollection("my")

# 查看集合
> show collections

# 删除集合
> db.my.drop()

隐式创建参考文档的操作

3.3文档的操作

3.3.1文档的插入

演示:向comment集合插入一条数据:

> user my

> db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明 媚","userid":"1001","nickname":"Rose","createdatetime":new Date(),"likenum":NumberInt(10),"state":null})

当返回下列信息时,就代表插入成功

WriteResult({ "nInserted" : 1 })

说明:

  • comment集合如果不存在,则会隐式创建

  • mongo中的数字,默认情况下是double类型,如果要存整型,必须使用函数NumberInt(整型数字),否则取出来就有问题了。

  • 插入当前日期使用 new Date()

  • 插入的数据没有指定 _id ,会自动生成主键值

  • 如果某字段没值,可以赋值为null,或不写该字段。

注意:

  • 文档中的键/值对是有序的。

  • 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。

  • MongoDB区分类型和大小写。

  • MongoDB的文档不能有重复的键。文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

  • 键不能含有\0 (空字符)。这个字符用来表示键的结尾。

  • .和$有特别的意义,只有在特定环境下才能使用。

  • 以下划线"_"开头的键是保留的(不是严格要求的)。

演示:插入多条数据

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"}, {"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船 长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"}, {"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯 撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"}, {"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫 嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08- 06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"} ]);

3.3.2文档的基本查询

查询所有:

> db.comment.find()
{ "_id" : ObjectId("6249a57a5e43b07ec991c633"), "articleid" : "100000", "content" : "今天天气真好,阳光明 媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2022-04-03T13:47:38.051Z"), "likenum" : 10, "state" : null }

这里每条文档会有一个叫_id的字段,这个相当于原来关系数据库中表的主键,当在插入文档记录时没有指定该字段,MongoDB会自动创建,其类型是ObjectID类型。

如果在插入文档记录时指定该字段也可以,其类型可以是ObjectID类型,也可以是MongoDB支持的任意类型。

查询单个:

> db.comment.find({articleid:"100001"})
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 1000, "state" : "1" }
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
{ "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船 长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯 撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }

多个结果只想要一条:

> db.comment.findOne({articleid:"100001"})
{
        "_id" : "1",
        "articleid" : "100001",
        "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。",
        "userid" : "1002",
        "nickname" : "相忘于江湖",
        "createdatetime" : ISODate("1970-01-01T00:00:00Z"),
        "likenum" : 1000,
        "state" : "1"
}

投影查询(只显示想要的字段):

> db.comment.findOne({articleid:"100001"},{userid:1,nickname:1})
{ "_id" : "1", "userid" : "1002", "nickname" : "相忘于江湖" }

注意:

  • 插入时指定了_id,则主键就是该值
  • 如果某条数据插入失败,将会终止插入,但已经插入成功的数据不会回滚。因此批量插入由于数据较多容易出现失败,可以使用try catch块进行异常捕捉处理。例如:
try { 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"}, {"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船 长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"}, {"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯 撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"}, {"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫 嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08- 06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"} ]); } catch (e) { print (e); }

3.3.3文档的更新

覆盖的修改:

如果想修改_id为1的记录,点赞量为1001,输入以下语句即可

db.comment.update({_id:"1"},{likenum:NumberInt(1001)})

执行后,会发现这条数据除了likenum字段其他字段不见了
MongoDB扫盲-黑马_第3张图片
局部修改:

为了解决上述的问题,需要使用修改器$set来实现,命令如下:

db.comment.update({_id:"2"},{$set:{likenum:NumberInt(889)}})

MongoDB扫盲-黑马_第4张图片
批量修改:

更新所有用户为1003的用户昵称为凯撒大帝

# 默认只修改第一条数据
db.comment.update({userid:"1003"},{$set:{nickname:"凯撒2"}})

# 修改所有符合条件的数据
db.comment.update({userid:"1003"},{$set:{nickname:"凯撒大帝"}},{multi:true})

列值增长的修改:

如果我们想实现某列值在原有值的基础上增加或减少,可以使用$inc运算来实现

例如:对3号数据的点赞数,每次递增1

db.comment.update({_id:"1003"},{$inc:{likenum:NumberInt(1)}})

3.3.4删除文档

删除所有数据:

db.comment.remove({})

删除_id=1的数据

db.comment.remove({_id:"1"})

3.3.5分页查询

统计查询:

(1)统计所有记录数

db.comment.count()

(2)按条件统计记录数

db.comment.count({userid:"1003"})

分页列表查询:

使用limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据

如果想返回指定条数的记录,可以在find()后调用limit()来返回结果,默认值20,例如:

db.comment.find().limit(2)

skip()方法同样接受一个数字参数作为跳过的记录条数。即前N个不要,默认是0

db.comment.find.skip(1)

分页查询需求:每页2个,从第二页开始。即跳过前两条数据,接着显示第3和第条数据

db.comment.find().skip(2).limit(1)

3.3.5排序查询

sort()方法对数据进行排序,可以指定排序的字段,并使用1和-1来指定排序的方式,其中1为升序,-1为降序

例如:对userid进行升序,对likenum进行降序

db.comment.find().sort({userid:1,likenum:-1})

3.3.6模糊查询

MongoDB的磨合查询是通过正则表达式的方式实现的

查询评论内容包含“开水”的文档

db.comment.find({content:/开水/})

查询评论的内容是以“专家”开头的

db.comment.find({content:/^专家/})

3.3.7比较查询

比较查询的格式如下:

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:NmuberInt(700)}})

3.3.8包含查询

包含使用$in操作符,示例:查询评论的集合中userid字段包含1003或1004的文档

db.comment.find(userid:{$in:["1003","1004"]})

相似的,不包含使用$nin操作符即可。

3.3.8条件连接查询

如果需要查询同时满足两个以上的条件,需要使用$and操作符将条件进行关联,相当于SQL的and,格式为:

$and:[{},{},{}]

示例:查询评论集合中likenum大于等于700并且小于2000的记录

db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]})

如果两个条件之间是或者的关系,使用or操作符进行关联,与and的使用方式相同,格式为:

$or:[{},{},{}]

示例:查询评论集合中userid为1003,或者点赞数小于1000的记录

db.comment.find({$or:[{userid:"1003"},{likenum:{$lt:NumberInt(1000)}}]})

4、索引

4.1索引概述

索引是特殊的数据结构,他以易于遍历的形式存储数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作,此外,MongoDB还可以使用索引中的排序返回排序的结果。

4.2索引的类型

4.2.1单字段索引

MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引。
对于单个字段索引和排序操作,索引键的排序顺序(升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。

例如:在score字段上建立一个升序索引
MongoDB扫盲-黑马_第5张图片

4.2.2复合索引

MongoDB还支持多个字段的索引,即复合索引
复合索引中列出的字段顺序有重要意义,例如:如果复合索引由{userid:1,score:-1}组成,则索引首先按照userid正序排列,然后在每个userid的值内,再按照score排列(类似于MySQL的最佳左前缀)
MongoDB扫盲-黑马_第6张图片

4.2.3其他索引

地理空间索引、文本索引、哈希索引

4.3索引的管理

4.3.1索引的查看

返回一个集合中所有索引的数组

db.comment.getIndexes()

MongoDB扫盲-黑马_第7张图片
结果显示的是默认的_id索引,MongoDB在创建集合的过程中,在_id字段上创建一个唯一的索引,默认名字为_id_,该索引可防止客户端插入两个具有相同值的文档,不能在_id字段上删除此索引。

注意:该索引是唯一所以,即_id值是不能重复的,在分片集群中,通常使用_id作为分片键

4.3.2索引的创建

创建单字段索引,对userid字段建立升序索引:

db.comment.crateIndex({userid:1})

创建复合索引,对userid和nickname建立复合索引:

db.comment.createIndex({userid:1,nickname:-1})

4.3.3索引的删除

删除指定的索引:

db.comment.dropIndex({userid:1})

删除所有的索引

db.collection.dropIndexes()

4.4索引的使用

4.4.1执行计划

示例:查看根据userid查询数据的情况

> db.comment.find({userid:"1003"}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "articledb.comment",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "userid" : {
                                "$eq" : "1003"
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "userid" : 1,
                                        "nickname" : -1
                                },
                                "indexName" : "userid_1_nickname_-1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "userid" : [ ],
                                        "nickname" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "userid" : [
                                                "[\"1003\", \"1003\"]"
                                        ],
                                        "nickname" : [
                                                "[MaxKey, MinKey]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "DESKTOP-HL7VBD1",
                "port" : 27017,
                "version" : "4.0.12",
                "gitVersion" : "5776e3cbf9e7afe86e6b29e22520ffb6766e95d4"
        },
        "ok" : 1
}
>

关键点:“stage” : “COLLSCAN”, 表示全集合扫描

下面对userid建立唯一索引,再次查看执行计划

> db.comment.createIndex({userid:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "ok" : 1
}
>
>
> db.comment.find({userid:"1003"}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "articledb.comment",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "userid" : {
                                "$eq" : "1003"
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "userid" : 1
                                },
                                "indexName" : "userid_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "userid" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "userid" : [
                                                "[\"1003\", \"1003\"]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [
                        {
                                "stage" : "FETCH",
                                "inputStage" : {
                                        "stage" : "IXSCAN",
                                        "keyPattern" : {
                                                "userid" : 1,
                                                "nickname" : -1
                                        },
                                        "indexName" : "userid_1_nickname_-1",
                                        "isMultiKey" : false,
                                        "multiKeyPaths" : {
                                                "userid" : [ ],
                                                "nickname" : [ ]
                                        },
                                        "isUnique" : false,
                                        "isSparse" : false,
                                        "isPartial" : false,
                                        "indexVersion" : 2,
                                        "direction" : "forward",
                                        "indexBounds" : {
                                                "userid" : [
                                                        "[\"1003\", \"1003\"]"
                                                ],
                                                "nickname" : [
                                                        "[MaxKey, MinKey]"
                                                ]
                                        }
                                }
                        }
                ]
        },
        "serverInfo" : {
                "host" : "DESKTOP-HL7VBD1",
                "port" : 27017,
                "version" : "4.0.12",
                "gitVersion" : "5776e3cbf9e7afe86e6b29e22520ffb6766e95d4"
        },
        "ok" : 1
}
>

关键点:“stage” : “IXSCAN” ,基于索引的扫描

4.4.2涵盖的查询

当查询条件和查询的字段仅包含索引字段时,MongoDB直接从索引返回结果,而不扫扫描任何文档或将文档带入内存。

注意:类似于MySQL的索引覆盖

你可能感兴趣的:(面试题集锦,java)