MongoDB的学习Ⅰ(MongoDB的安装与说明、MongoDB语句、MongoDB索引)

一、关于MongoDB

MongoDB面向文档型 的数据库,也就是说MongoDB是一个基于分布式文件存储的数据库(非关系型数据库)MongoDB最像关系型数据库(MySQL)的非关系型数据库。它支持的数据结构非常松散,是一种类似于 JSON 的 格式叫BSON(二进制的JSON),所以它既可以存储比较复杂的数据类型,又相当的灵活。

MySql里面我们是一个个的数据表,但是在MongoDB里面是一个个的集合,集合里面是一个个的文档。

MySql里面的数据表中是一行一行的数据,但是在MongoDB里面的**集合**中是 一个个文档的集合,每个文档类似一行的数据。

MongoDB是以 键值对的形式保存数据 的。

MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

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

MongoDB最小存储单位就是文档(document)对象文档(document)对象对应于关系型数据库的行。数据在MongoDB中以
BSON(Binary-JSON)文档的格式存储在磁盘上。

MongoDB的特点:高性能、高可用性、高扩展性、丰富的查询支持

二、MongoDB的安装与自带的数据库

MongoDB是傻瓜式安装,读者可自行百度

自带的数据库:

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

百度盘文件(MongoDB与可视化工具的安装包):

https://pan.baidu.com/s/1gWWYn9WJ1iquIAZFjx-mlQ
提取码:fso1

如果资金富裕,小编还是建议您购买正版。

三、可视化工具的安装与连接数据库

工具是傻瓜式安装,读者可自行百度
不过在安装可视化工具时选择Shell-centric模式,且打开Studio 3T时有期限设置,需要购买:
可以点击这里获得该软件的永久洪荒之力

作者:MaNongXiaoGang
来源:https://www.jianshu.com/p/0be23482d4da

还是那句话,如果资金富裕,小编还是建议您购买正版。

可视化工具连接数据库

参考这里
作者:七里茶坊一厘米
来源:https://www.jianshu.com/p/b1d4158a4ee3

四、MongoDB一些指令

常用指令

show dbs // 查看已经存在的数据库

use 数据库名  //切换到指定的数据库(无论数据库是否存在 均可切换成功)

db  // 查看当前所在的数据库

db.getCollectionNames() //查看当前数据库下一共有哪些文档集合

文档的插入

db.集合名.insert(query,option)
这里的query就是增加的语句
option 为可选参数, 为对象类型,其下有两个属性:
ordered : 布尔值,默认true,可选。如果为真,则按顺序插入数组中的文档,如果为假,则执行无序插入
writeConcern : ,可选,抛出异常的级别

db.集合名.insert(文档)  //向指定的集合录入一条文档(如果集合不存在会自动创建)
//例如:  db.users.insert({user:"daotin",age:18})  

db.集合名.insert([文档1,文档2]) // 向指定的集合插入多条文档,如果集合不存在,则会自动创建集合
// 例如:db.users.insert([{user:"lvonve",age:10},{user:"wenran", age:20}])

// 插入多条数据或单条数据的其他写法
//db.集合名.insertMany([文档1,文档2])  插入多条数据
//db.集合名.insertOne(文档)            插入单条数据
db.users.insert([
    {username:"马云",age:58,height:167,friends:["马化腾","许家印","雷军","李彦宏","柳传志"]},
    {username:"许家印",age:52,height:177,friends:["马化腾","雷军","柳传志"]},
    {username:"雷军",age:48,height:174,friends:["马化腾","董明珠","柳传志"]},
    {username:"雷德承",age:18,height:180,friends:["马化腾","王健林","柳传志"]},
    {username:"王思聪",age:32,height:179,friends:["林更新","林缓存","陈赫","雷军"]}
])

注意:添加数据的时候会自动添加一个独一无二的idMongoDB区分类型和大小写,且MongoDB的文档不能有重复的键_id可以指定的(不指定时就是随机值)

数据库的删除

db.dropDatabase()

集合的创建

db.createCollection(name)				// 显式创建

向一个集合中插入一个文档的时候,如果集合不存在,则会自动创建集合(隐式创建)

集合的删除

db.集合.drop()

查询语句

db.集合名.find(query,projection)
这里的query就是查询的语句
projection:可选。指定要在与查询筛选器匹配的文档中返回的字段。若要返回匹配文档中的所有字段,请省略此参数。

简单查询
db.集合名.find()  // 查询指定的集合内所有数据
//{ "_id" : ObjectId("5c18e0aef024bd18615cc516"), "user" : "daotin", "age" : 18 }
//{ "_id" : ObjectId("5c18e188dc1d4d80df2f4ae6"), "user" : "lvonve", "age" : 10 }
//{ "_id" : ObjectId("5c18e188dc1d4d80df2f4ae7"), "user" : "wenran", "age" : 20 }

// 查询指定字段
db.集合名.find({筛选条件},{显示字段})

// 显示字段
// 显示user字段,不显示_id字段
db.users.find({},{_id:0, user:1}) // 显示的字段值为1,不显示的字段值为0
复杂查询
// 筛选条件
//条件格式:   属性名:{条件操作符:值} 
//条件操作符
//    $gt : 大于
//    $gte : 大于等于
//    $lt : 小于
//    $lte : 小于等于
//    $in : 包含其中任意一个  注意 $in操作符的值必须为数组类型
//    $all : 包含所有  值同上,必须为数组类型
//    $nin : 不包含其中任意一个 值要求同上
//    $ne : 不等于
//    $not : 对已定义好的条件进行取反 {属性:{$not:{条件}}}
//    $mod : 取模 (取余)   $mod:[x,y] 取所有除x余y的值
db.users.find({age:{$gt:35}},{_id:0}) // 筛选条件为年龄大于35
db.users.find({friends:{$in:["林更新"]}},{_id:0}) // 筛选条件为friends字段有林更新的。
db.users.find({friends:{$in:["林更新","雷军"]}},{_id:0}) // 筛选条件为friends字段有林更新或者有雷军的
db.users.find({friends:{$all:["马化腾","雷军"]}},{_id:0}) // 筛选条件为friends字段同时包含马化腾和雷军
db.users.find({friends:{$nin:["马化腾","雷军"]}},{_id:0}) // 筛选条件为friends字段不包含马化腾或者不包含雷军即可
db.users.find({age:18},{_id:0}) // 筛选条件为age为18的文档
db.users.find({age:{$ne:18}},{_id:0}) // 筛选条件为age不为18的文档
db.users.find({age:{$not:{$gt:18}}},{_id:0}) // 筛选条件为年龄小于等于18
db.users.find({age:{$mod:[3,0]}},{_id:0})  // 筛选条件为age/3余数为0的文档

查询的方式都是以对象的形式查询的

模糊查询

1、db.goods.find({name:/joe/ig})
2、db.goods.find({name:{$regex:/joe/ig}})			// 注意这里是regex而不是regexp
3、db.goods.find({goodsName:{$regex: "joe", $options:"ig"}})
var reg = new RegExp("joe", "ig");
4、db.goods.find({name:reg})
5、db.goods.find({name:{$regex:reg}})
// 以上5种写法均可

推荐前两种方法,后面的三种有意想不到的地方(本人理解不了)

条件“且”和“或”

注意在写条件时,同一字段需要写在一个花括号内
如:

 db.users.find({ age: { $gt: 30 }, age: { $lt: 40 } }, { _id: 0 })	// 有毛病的语句

db.users.find({ age: { $gt: 30 ,$lt: 40 } }, { _id: 0 })	// 没毛病的语句
条件:且
db.users.find({$and:[{条件1},{条件2}]},{_id:0}) 		// 注意and后面是[]
db.users.find({条件1,条件2},{_id:0})					// 隐式and操作
db.users.find({age:{$gt:35},friends :{$in:["雷军"]}},{_id:0}) // 年龄大于35,并且friends中有雷军的
db.users.find({ age: { $gt: 30 ,$lt: 40 } }, { _id: 0 })	// 年龄大于30小于40
条件:或
db.users.find({$or:[{条件1},{条件2}]},{_id:0}) 		// 注意or后面是[]
db.users.find({$or:[{age:{$gt:35}},{friends:{$in:["雷军"]}}]},{_id:0})  // 年龄大于35,或者friends中有雷军的
条件:且和或都有
db.users.find({条件1,$or:[{条件2},{条件3}]},{_id:0}) // 满足条件1,并且满足条件2或者条件3中的一个
db.users.find({age:{$gt:30},$or:[{height:{$lt:175}},{friends:{$in:["许家印"]}}]},{_id:0}) // 年龄大于30 ,并且身高小于175或者认识许家印

and和or后面必须跟[],都是在属性之前的

条件“都不”

db.mydata.find({$nor: [{ age: { $lt: 30 } }, { age: { $gt: 40 } }] }, { _id: 0 })		// 年龄30到40之间(包括30,40)

nor后面必须跟[],nor是在属性之前的,如:{$nor: [{ age: { $lt: 30 } }, { age: { $gt: 40 } }] }

条件“非”

db.users.find({username:{ $not: { $regex: /雷/ig } } }, { _id: 0 })	// 名字不包括“雷”

db.mydata.find({age:{ $not: [{ $lt: 30 }, { $gt: 40 }] } }, { _id: 0 })	// Error:$not needs a regex or a document

{ $not: { $gt: 1.99 } } 不同于$lte操作,{ $lte: 1.99 }操作只会返回price字段存在并且小于等于1.99的字段,且not后面不能跟[],not是在属性之后的,如:{username:{ $not: { $regex: /雷/ig } } }

统计查询

db.集合名.count(query, options)
这里的query就是上文的查询语句
options 为可选参数, 为文档类型,用于修改计数的额外选项(一般不选)

db.users.find({age:{$gt:35}},{_id:0}).count() // 统计年龄大于35岁的文档个数

默认情况下 count方法(无参时) 返回符合条件的全部记录条数。

其他条件操作

.limit(n) //取满足条件的头n条数据
.skip(n) //跳过n条数据再取数据
.sort({第一排序条件,第二排序条件,.....})  //按照属性进行排序
.skip(m).limit(n) //跳过m条数据 再取头n条数据 (调用顺序没有讲究,都是先跳过数据再取数据)

//示例
db.users.find({},{_id:0}).limit(3) // 取users集合中所有文档的前3个
db.users.find({},{_id:0}).limit(3).skip(3) // 取users集合中敲过前三个后取目前文档的前3个


db.users.find({},{_id:0,age:1}).sort({age:1})// 按照年龄升序排列(正数为升序)
db.users.find({},{_id:0,age:1}).sort({age:-1})// 按照年龄降序排列(负数为升序)
db.users.find({},{_id:0,age:1,height:1}).sort({age:1,height:1})// 按照年龄升序排列,如果年龄相同,按照身高升序排列
db.users.find().skip(1).limit(5).sort({ age: 1 })	// 结果与skip、limit、sort的顺序无关,都是执行sort=>skip=>limit

// 设计翻页的时候,一般会这么用:
 db.users.find().limit(y).skip((x-1)*y)

提示:
skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit()和命令编写顺序无关

修改语句

db.集合名.update(query,{修改器:{属性:值}},option)
这里的query就是上文的查询语句
option 为可选参数, 为对象类型,其下有六个属性(主要关注前两个参数即可):
multi : 布尔值,默认false (只更新找到的第一条记录),true(将查找结果全部更新)
upsert : 布尔值,当没有符合条件的数据时,是否创建该数据,默认false
writeConcern : ,可选,抛出异常的级别
collation : ,可选,指定要用于操作的校对规则。
arrayFilters : ,可选。一个筛选文档数组,用于确定要为数组字段上的更新操作修改哪些数组元素
hint :,可选。指定用于支持查询谓词的索引的文档或字符串。

//修改器
//	$set : 重新赋值,若没有该字段则自动添加
//	$inc : 对值进行叠加30(增),或叠加-30(减) 适用于数字类型的值 
//	$unset : 删除整个属性(包括属性名及属性值)

//数组修改器
//	$push : 给数组类型的值添加一个新元素(最后)
//	$addToSet : 给数组添加一个新值 (该方法不会重复添加已经存在的值,同样的内容只添加一次)
//	$pop : 从尾部删除一条数据,且只能是1(从尾部删除一条数据) 或者-1  (从头部删除一条数据)
//	$pull : 删除数组内指定元素  {$pull:{属性:值}} 

//示例:
db.users.update({username:"马云"},{$set:{age:55}}) // 设置马云文档的age为55
db.users.update({username:"马云"},{$inc:{age:2}})) // 设置马云的age在原来的基础上+2,如果是-2的话是减2
db.users.update({username:"马云"},{$unset:{age:1}}) // 删除马云的age属性,这里age设置的值可以任意(可以不设置)。

db.users.update({username:"马云"},{$push:{friends:"Daotin"}}) // 给马云的friends属性的最后增加一个值“Daotin”
db.users.update({username:"马云"},{$pop:{friends:1}}) // 给马云的friends属性从最后删除一个值。这里指令friends的值不可随意。
db.users.update({username:"王思聪"},{$pull:{friends:"林更新"}}) // 删除王思聪的friends属性中的林更新

注意:在默认情况下,修改操作只会操作第一条符合条件的数据。

删除语句

db.集合名.remove(query,option)
option:为可选参数,为对象类型,拥有属性
justOne: 是否只删除第一条符合条件的数据,默认false
writeConcern : ,可选,抛出异常的级别

db.users.remove({username:"涂涂"}) // 删除username属性值为“涂涂”的记录
db.users.remove({})				// 把数据库内的users集合的数据全部删除,跑路专用

注意:默认情况下 会删除所有符合条件的数据

五、MongoDB索引概述

索引支持在MongoDB中高效地执行查询。如果没有索引MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
如果就算存在适当的索引MongoDB在使用该索引时也必须限制检查的文档数。
索引特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分

MongoDB索引使用B树数据结构(确切的说是B-Tree,MySQL是B+Tree)

六、索引的类型

单字段索引

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

复合索引

MongoDB支持多个字段用户定义索引,即复合索引(Compound Index)。
复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然后在userid的值相同时,再在按score倒序排序。

其他索引

地理空间索引(Geospatial Index)

为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引。

文本索引(Text Indexes)

MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如“the”、“a”、“or”),而将集合中的词作为词干,只存储根词。

哈希索引(Hashed Indexes)

为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。

七、 索引的管理操作

索引的查看

db.collection.getIndexes()					// 返回一个集合中的所有索引的数组。

// 结果
[
	{
		"v" : 2,
		"key" : {
		"_id" : 1
	},
		"name" : "_id_",
		"ns" : "articledb.comment"
	}
]

MongoDB创建集合的过程中,在 _id 字段自动创建一个唯一的索引默认名字为 _id ,该索引可防止客户端插入两个具有相同值的文档,您不能在_id字段上删除此索引。
注意该索引是唯一索引,因此值不能重复,即 _id 值不能重复的。在分片集群中,通常使用 _id 作为片键。

索引的创建

db.collection.createIndex(keys, options)
Parameter Type Description
keys document 包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。对于字段上的升序索引,请指定值1;对于降序索引,请指定值-1。比如: {字段:1或-1} ,其中1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。另外,MongoDB支持几种不同的索引类型,包括文本、地理空间和哈希索引。
下面是options 下面是options 下面是options
background Boolean 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加"background" 可选参数。 “background” 默认值为false。
unique Boolean 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name string 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
sparse Boolean 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSeconds integer 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
v indexversion 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weights document 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_language string 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_override string 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为language.

其他的请参看官网

【示例】

(1)单字段索引示例:对 userid 字段建立索引:

> db.comment.createIndex({userid:1})			// 语句
{												// 结果
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}

可以查看一下索引

> db.comment.getIndexes()						// 语句
[												// 结果
	{
		"v" : 2,
		"key" : {
			"_id" : 1				// 自带的索引
		},
		"name" : "_id_",
		"ns" : "articledb.comment"
	},
	{
		"v" : 2,
		"key" : {
			"userid" : 1			// 自定义的索引
		},
		"name" : "userid_1",
		"ns" : "articledb.comment"
	}
]

(2)复合索引:对 userid 和 nickname 同时建立复合(Compound)索引

> db.comment.createIndex({userid:1,nickname:-1})	// 语句
{												// 结果
	"createdCollectionAutomatically" : false,		
	"numIndexesBefore" : 2,
	"numIndexesAfter" : 3,
	"ok" : 1
}

查看一下索引

> db.comment.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1			// 自带索引
		},
		"name" : "_id_",				
		"ns" : "articledb.comment"
	},
	{
		"v" : 2,
		"key" : {
			"userid" : 1,			// 定义索引
			"nickname" : -1
		},
		"name" : "userid_1_nickname_-1",
		"ns" : "articledb.comment"
	}
]

索引的移除

指定索引的移除
db.collection.dropIndex(index)		// index为指定要删除的索引

> db.comment.dropIndex({userid:1})
{ "nIndexesWas" : 3, "ok" : 1 }
所有索引的移除
db.collection.dropIndexes()			// 删除 collection集合中所有索引。

> db.comment.dropIndexes()
{
	"nIndexesWas" : 2,
	"msg" : "non-_id indexes dropped for collection",
	"ok" : 1
}

提示_id 的字段的索引是无法删除,只能删除非 _id 字段的索引。

索引的使用

执行计划

分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。
那么,通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划(explain) 查看。

db.collection.find(query,options).explain(options)

例如:
未添加索引 的查询结果,低效

> db.comment.find({userid:"1003"}).explain()		// 语句


{											// 结果
	"queryPlanner" : {	
		"plannerVersion" : 1,
		"namespace" : "articledb.comment",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"userid" : {
				"$eq" : "1003"
			}
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",			// 关键点:"stage"为"COLLSCAN", 表示全集合扫描
			"filter" : {
				"userid" : {
					"$eq" : "1003"
				}
			},
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"serverInfo" : {
		"host" : "9ef3740277ad",
		"port" : 27017,
		"version" : "4.0.10",
		"gitVersion" : "c389e7f69f637f7a1ac3cc9fae843b635f20b766"
	},
	"ok" : 1
}

下面对userid建立索引:

> db.comment.createIndex({userid:1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}

再次查看执行计划,高效

> db.comment.find({userid:"1013"}).explain()			// 语句


{												// 结果
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "articledb.comment",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"userid" : {
				"$eq" : "1013"
			}
		},
		"winningPlan" : {
		"stage" : "FETCH",
		"inputStage" : {
			"stage" : "IXSCAN",		// 关键点:"stage"为"IXSCAN", 表示索引扫描
			"keyPattern" : {
				"userid" : 1
			},
			"indexName" : "userid_1",
			"isMultiKey" : false,
			"multiKeyPaths" : {
				"userid" : [ ]
			},
			"isUnique" : false,
			"isSparse" : false,
			"isPartial" : false,
			"indexVersion" : 2,
			"direction" : "forward",
			"indexBounds" : {
				"userid" : [
						"[\"1013\", \"1013\"]"
					]
				}
			}
		},
		"rejectedPlans" : [ ]
	},
	"serverInfo" : {
		"host" : "9ef3740277ad",
		"port" : 27017,
		"version" : "4.0.10",
		"gitVersion" : "c389e7f69f637f7a1ac3cc9fae843b635f20b766"
	},
	"ok" : 1
}
涵盖的查询

当查询条件查询的投影仅包含索引字段 时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。 这些覆盖的查询可以非常有效。
例如:

 db.comment.find({userid:"1003"},{userid:1,_id:0})		// 高效的,查询条件与查询的投影只包含索引字段

本文只用于个人学习与记录

你可能感兴趣的:(MongoDB)