Mongdb—入门(介绍、安装、操作)

1、mongodb是什么

mongodb是一个高性能的、开源的、无模式的文档型数据库,使用C++语言开发

随着业务领域的发展,数据的扩大,逐渐互联网开发演变成了超大规模和高并发模型,这样在传统的数据库领域就显得力不从心了
比如:
1、在很多电商型网站,他们的QPS基本上都会在上每秒的上万次读写请求。特别是在默写节日比如:双十一、双十二;每秒的读写请求甚至在上百万;这对于关系型数据库来说,每秒钟上万次的SQL写数据请求,硬盘的IO就已经达到了瓶颈,无法承受了
2、比如新浪微博这样的网站,每天大概至少产生100亿条用户的动态信息;如果我们把100亿条的信息存储在关系型数据的一张表里面,在做查询的时候,效率是非常低的。那么mongodb的出现,并不是为了解决高性能的并发读写的,是为了能让我在处理海量数据的存储的同时,还能具有非常强大的查询性能
mongodb的特点
mongodb的最大特点就是介于关系型数据库和菲关系型数据库之间的产品,虽然mongodb支持的数据结构非常的松散(BSON格式),但是mongodb是非关系型中功能最丰富的,也是最像关系型数据库的东西。所以在一些数据量较大,而且关系比较复杂的场景情况下,mongodb是一个非常不错的选择;

2、mongodb特点

1、面向集合

我们在使用关系型数据也好,非关系型数据也好,往往我们的数据都是存储在一个叫做表的单位中,但是mongodb是将数据分组存储在集合中,我们也可以理解成:mongodb中的集合就是类似关系型数据库中的表

2、模式自由

在关系型数据库中,我们插入数据都是要按照表的结构去插入,哪怕没有这个字段,仍然需要在这一行中显示一个null
但是在mongodb中就没有这个限制,你可以随意的插入你想要的模式: {name:”zhangsan” , age:18} {name:”zhangsan” , age:18 , school:”qinghua”}

3、文档型

mongodb中存储的数据是键值对的集合,键是字符串,值可以是任何的类型 数据格式我们叫做BSON(bson就是json的变体,对json进一步的优化的格式)
这种格式可以进行高效的二进制数据存储和,甚至可以进行存储超大的对象(比如我们有一些视频需要去存储,使用mongodb时完全可以的)
mongodb的数据逻辑结构: 文档+集合+数据库 = mongodb的逻辑结构

然后我们在和关系型数据库在逻辑结构的对比

 

3mongodb的内部结构

在MongoDB中,文档是对数据的抽象,它被使用在Client端和Server端的交互中。所有的Client端(各种语言的Driver)都会使用这种抽象,它的表现形式就是我们常说的BSON(Binary JSON )。

BSON是一个轻量级的二进制数据格式。MongoDB能够使用BSON,并将BSON作为数据的存储存放在磁盘中。

当Client端要将写入文档,使用查询等等操作时,需要将文档编码为BSON格式,然后再发送给Server端。同样,Server端的返回结果也是编码为BSON格式再放回给Client端的。

4、mongodb的安装

1curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.6.tgz 



2tar -zxvf mongodb-linux-x86_64-3.0.6.tgz # 解压


5、mongodb启动服务端

1、在启动服务的时候一定要预选创建好mongodb存放数据的目录以及日志文件存放的目录:

2、bin/mongod --dbpath /path/to/database --logpath /path/to/log --fork --port 27017

参数解释:

--dbpath 数据存储目录

--logpath 日志存储目录

--port 运行端口(默认27017)

--fork 后台进程运行

因为每次都需要启动服务,并且传入需要的参数,为了方便,我们可以自己写一个简单的shell脚本来更方便的启动

#! /bin/bash

clear

if [ ! -n "$1" ]; then

        echo "============[请输入端口号!]================"

        exit

fi

soft_path=/export/servers/mongodb

echo "========================启动服务,输入的端口号为:$1 ==============================="

$soft_path/bin/mongod --dbpath $soft_path/data_path/ --logpath $soft_path/log_path/server.log --fork --port $1

echo "========================================================================"

echo "ps -ef | grep mongodb:"

ps -ef | grep mongodb

6、mongodb客户端的登录

Bin/mongo


7、DDL操作

创建数据库
1、查看当前的mongodb中有哪些数据库:

show dbs


2、使用db可以查看当前使用的是哪个库

db

其实我们可以使用help命令来帮助我们,当我们不知道有哪些具体操作的时候,我们可以使用db.help()


3、使用use dbname来进行切换数据库或者创建数据库,系统就会延迟创建数据库

只有当我们在当前的数据库中真正的插入了某些东西以后,才可以显示出我们刚才use的数据库
 

use dbname

我们接下来可以使用db来查看当前使用的数据:
db course1
然后使用show dbs查看现在有哪些的数据库:

show dbs 

这时候系统不会立马创建数据库,而是等到我们后面对数据库有了操作之后才会进行创建,是一种延迟的加载机制,很类似spark里面的rdd延迟加载


我们也可以尝试在新建的库中添加一个collection,这样我们在查看是否有库显示的创建

db.storeCollection.save({name:'zhangsan',age:18,country:'china'}) WriteResult({ "nInserted" : 1 }) 


然后我们在使用show dbs就可以查看到; show dbs; 

删除数据库
直接使用db.dropDatabase()即可删除数据库

db.dropDatabase()



创建集合
显示的创建

createCollection()命令的基本语法如下:
db.createCollection(name, options)
在命令中,name 是要创建的集合的名称。 options是一个文档,用于指定集合的配置。

参数

类型

描述

name

String

要创建的集合的名称

options

Document

(可选)指定有关内存大小和索引的选项


options参数是可选的,因此只需要指定集合的名称。 以下是可以使用的选项列表:

字段

类型

描述

capped

Boolean

(可选)如果为true,则启用封闭的集合。上限集合是固定大小的集合,它在达到其最大大小时自动覆盖其最旧的条目。 如果指定true,则还需要指定size参数。

autoIndexId

Boolean

(可选)如果为true,则在_id字段上自动创建索引。默认值为false

size

数字

(可选)指定上限集合的最大大小(以字节为单位) 如果cappedtrue,那么还需要指定此字段的值。

max

数字

(可选)指定上限集合中允许的最大文档数。


在插入文档时,MongoDB首先检查上限集合capped字段的大小,然后检查max字段


实例:

创建集合

db.createCollection("mycol", {capped : true, autoIndexId : true, size : 6142800, max : 10000 })


使用show collections来查看:

show collections

其中的system.index是存储索引的



隐式的创建

db.mycol2.insert({type:"news",title:"yule"})

db.mycol2.insert({name:"lisi",age:18})


通过查询的方式进行验证

db.mycol2.find()

当我们创建完集合之后,我们可以去磁盘上看下,是否把数据刷到了磁盘。这样我们下次登录还可以继续使用上一次的数据

同样,对于集合的操作,当我们不知道具体的命令操作的时候,我们可以使用db.database_name.coll_name来进行提示


删除集合

db.mycol.drop() 



8CURD操作

1、插入

Mongodb给我们提供了像一个集合中插入数据的方法:

db.collection.insertOne()

db.collection.insertMany()

这两个方法都是在3.2版本中出现的

然后我们在看下如何进行插入操作

单挑插入:

db.inventory.insertOne(

   { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }

)

然后查询验证:

db.inventory.find()

多条插入:

db.inventory.insertMany([

   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },

   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },

   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }

])

然后查询验证:

db.inventory.find()

2.6老版本中更新的命令:

db.products.insert( { item: "card", qty: 15 } )

这个老版本的insert语句有一些参数可以提供我们进行选择

参数

类型

描述

document

文档或数组

要插入到集合中的文档或一系列文档

writeConcern

文件

writeConcern包括:wjtimeout操作

ordered

布尔

可选的。如果true对数组中的文档执行有序的插入操作,并且如果其中一个文档发生错误,则MongoDB将返回而不处理数组中剩余的文档。

如果false执行无序插入,并且某个文档发生错误,则继续处理数组中的其余文档。

默认为true

writeConcern

MongoDB支持的WriteConncern选项如下

w: 数据写入到number个节点才向用客户端确认

{w: 0} 对客户端的写入不需要发送任何确认,适用于性能要求高,但不关注正确性的场景

{w: 1} 默认的writeConcern,数据写入到Primary就向客户端发送确认

{w: majority} 数据写入到副本集大多数成员后向客户端发送确认,适用于对数据安全性要求比较高的场景,该选项会降低写入性能

j: 写入操作的journal持久化后才向客户端确认

默认为”{j: false},如果要求Primary写入持久化了才向客户端确认,则指定该选项为true

wtimeout: 写入超时时间,w的值大于1时有效

当指定{w: }时,数据需要成功写入number个节点才算成功,如果写入过程中有节点故障,可能导致这个条件一直不能满足,从而一直不能向客户端发送确认结果,针对这种情况,客户端可设置wtimeout选项来指定超时时间,当写入过程持续超过该时间仍未结束,则认为写入失败。

例子:

db.products.insert(

    { item: "envelopes", qty : 100, type: "Clasp" },

    { writeConcern: { w: "majority", wtimeout: 5000 } }

)

【注意:】另外当我们插入单条文档的时候,我们会发现执行成功之后是会返回给我们一个WriteResult 对象的

注意:

1、在mongodb中,_id是一个唯一的字段,并且是个主键;我们可以不写,系统会自动生成

2mongodb中所有的单挑操作其实都是原子性的,要么成功,要么不成功

2、删除文档

首先添加数据:

db.inventory.insertMany( [

   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },

   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },

   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },

   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },

   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },

]);

删除一条数据

db.mycol1.remove({fild1:0}) 删除fild1为0的操作

删除全部数据

db.inventory.remove({})

按条件删除所有的数据

当然在3.2版本出来之后,更新了一些删除的新命令:

比如:

删除一条数据:

db.mycol1.deleteOne({_id:1})

同样可以删除多条的数据:

db.mycol1.deleteMany({status:"A"})

这条命令的意思是说,把匹配到的数据全部删除


3、更改文档

mongodb的老版本中,更改文档的操作是

db.collection.update(criteria,objNew,upsert,multi)

参数说明:

criteria:用于设置查询条件的对象

objNew:用于设置更新内容的对象

upsert:如果记录已经存在,更新它,否则新增一个记录,取值为true或者false

multi:如果有多个符合条件的记录,是否全部更新,取值为true或者false

注意:默认情况下,只会更新第一个符合条件的记录

一般情况下后两个参数分别为0,1 ,即:

db.collection.update(criteria,objNew,0,1)

例子:

> db.classes.insert({"name":"c1","count":30})  

> db.classes.insert({"name":"c2","count":30})  

> db.classes.find()  

示例1:把count大于20class name修改为c3

> db.classes.update({"count":{$gt:20}},{$set:{"name":"c3"}})  

> db.classes.find()  

上面的操作中我们把upsertmulti全部设置成了false,那么只会更改符合条件的一条记录

示例2:把count大于20class name修改为c4,设置multitrue

> db.classes.update({"count":{$gt:20}},{$set:{"name":"c4"}},false,true)  

> db.classes.find()  

2中,我们把multi设置成了true,那么符合条件的全部被更改

示例3: 把count大于50class name修改为c5,设置upserttrue

> db.classes.update({"count":{$gt:50}},{$set:{"name":"c5"}},true,false)  

> db.classes.find()  

3中,把upserttrue,因为数据中没有count大于50的,所以会新创建一条数据


Mongodb3.6版本中为我们提供了这样的方法:

db.collection.updateOne()

db.collection.updateMany()

db.collection.replaceOne()

首先插入一部分数据:

db.inventory.insertMany( [

   { item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" },

   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },

   { item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" },

   { item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" },

   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },

   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },

   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },

   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },

   { item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" },

   { item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" }

]);

3、开始进行更改操作:

(1):更新单个文档

db.inventory.updateOne(

   { item: "paper" },

   {

     $set: { "size.uom": "cm", status: "P" },

     $currentDate: { lastModified: true }

   }

)

我们使用 $set来更改item中为paper的字段

其中符合字段size下面有一个uom,我们改成cm; 然后status改成p

(2):更改多个文档

db.inventory.updateMany(

   { "qty": { $lt: 50 } },

   {

     $set: { "size.uom": "in", status: "P" },

     $currentDate: { lastModified: true }

   }

)

把其中的qty字段小于50的操作,全部更改

(3):替换文档

替换文档是除了_id外,所有的字段都是可以进行替换的,甚至替换文档可以具有与原始文档不同的字段;

db.inventory.replaceOne(

   { item: "paper" },

   { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }

)

4、批量操作

在上面的操作中我们已经展示了:insertMany的批量插入方法

但是:MongoDB也为客户提供其他批量执行写操作的能力;

 

db.collection.bulkWrite()方法提供了执行批量插入,更新和删除操作的功能

其中对于写入的操作,mongodb支持批量的有序插入和无序插入

当我们使用有序插入的过程中,如果期间出现了异常,那么mongodb会停止剩下的插入操作

但是当我们使用无序的插入,即便出了问题,仍然会继续执行后面的操作

从性能角度分析,有序的插入,在操作执行时间上要比无序的慢很多,因为有有序的操作必须要等待上一个执行完毕;那么系统默认在我们进行批量操作的时候是有序的操作

首先我们先插入三条数据:

db.characters.insertMany([

{ "_id" : 1, "char" : "Brisbane", "class" : "monk", "lvl" : 4 },

{ "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 },

{ "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }

])

然后我们在使用批量的有序插入:

db.characters.bulkWrite(

      [

         { insertOne :

            {

               "document" :

               {

                  "_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4

               }

            }

         },

         { insertOne :

            {

               "document" :

               {

                  "_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3

               }

            }

         },

         { updateOne :

            {

               "filter" : { "char" : "Eldon" },

               "update" : { $set : { "status" : "Critical Injury" } }

            }

         },

         { deleteOne :

            { "filter" : { "char" : "Brisbane"} }

         },

         { replaceOne :

            {

               "filter" : { "char" : "Meldane" },

               "replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }

            }

         }

      ]

   );

批量的更改操作:

首先插入数据:

db.enemies.insertMany([

{ "_id" : 1, "char" : "goblin", "rating" : 1, "encounter" : 0.24 },

{ "_id" : 2, "char" : "hobgoblin", "rating" : 1.5, "encounter" : 0.30 },

{ "_id" : 3, "char" : "ogre", "rating" : 3, "encounter" : 0.2 },

{ "_id" : 4, "char" : "ogre berserker" , "rating" : 3.5, "encounter" : 0.12}

])

然后进行批量的更改:

db.enemies.bulkWrite(

      [

         { updateMany :

            {

               "filter" : { "rating" : { $gte : 3} },

               "update" : { $inc : { "encounter" : 0.1 } }

            },

         },

         { updateMany :

            {

               "filter" : { "rating" : { $lt : 2} },

               "update" : { $inc : { "encounter" : -0.25 } }

            },

         },

      

         { insertOne :

            {

               "document" :

                  {

                     "_id" :5, "char" : "ogrekin" , "rating" : 2, "encounter" : 0.31

                  }

            }

         }

      ],

      { writeConcern : { w : "majority", wtimeout : 100 } }

   );

在这里,我们进行逻辑上的判断,然后进行批量的更改操作

5、查询操作:

创建集合

db.inventory.insertMany([

   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },

   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },

   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },

   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },

   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }

]);

 

1、查询所有数据

db.inventory.find( {} )

2、按条件查询

db.inventory.find( { status: "D" } )

3、$in的操作

如果我们想查询status带有A的 或者 带有D的:

db.inventory.find( { status: { $in: [ "A", "D" ] } } )

4、and操作

想查询statusA 并且qty<30

db.inventory.find( { status: "A", qty: { $lt: 30 } } )

5、or的操作

假如我们想查询statusA 或者 qty<30的数据

db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )

6、多条件组合查询

在让我们来一个稍微复杂点的操作:

我们此时想查询:status=A并且qty < 30 或者item中以p为开头的

db.inventory.find( {

     status: "A",

     $or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]

} )

7、嵌套的查询方式

首先插入数据:

db.inventory.insertMany( [

   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },

   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },

   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },

   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },

   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }

]);

例子1:查询size: { h: 14, w: 21, uom: "cm" }这一条数据

db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } )

需要注意的是这个查询内部结构的顺序,如果顺序不对是查询不出来的,比如:

db.inventory.find(  { size: { w: 21, h: 14, uom: "cm" } }  )

列子2:带点符号的嵌套查询

db.inventory.find( { "size.uom": "in" } )

:

8、查询数组的方法

1、插入数据

db.inventory.insertMany([

   { item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] },

   { item: "notebook", qty: 50, tags: ["red", "blank"], dim_cm: [ 14, 21 ] },

   { item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] },

   { item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] },

   { item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] }

]);

列子1:查询字段tags 值是包含两个元素"blank", "red" 的数组的所有文档(顺序必须一致)

db.inventory.find( { tags: ["red", "blank"] } )

列子2:查询字段tags 值是包含两个元素"blank", "red" 的数组的所有文档(不考虑顺序)

db.inventory.find( { tags: { $all: ["red", "blank"] } } )

$all  , 意思是只要包含了redblank 不管顺序是什么样的】

列子3:查询所有文章中dim_cm数组的第二个参数大于25的所有文档

db.inventory.find( { "dim_cm.1": { $gt: 25 } } )

列子4:查询tags数组长度大于3的所有文章

db.inventory.find( { "tags": { $size: 3 } } )

9、查询null或者丢失的字段

首先插入数据:

db.inventory.insertMany([

   { _id: 1, item: null },

   { _id: 2 }

])

然后:

db.inventory.find( { item: null } ) 然后我们会发现查询出了所有的字段,这是因为itrm:null会查询出匹配到的null值以及不包含item字段的文章

练习

上面讲了不少的内容,接下来需要我们做一个练习,然后借着练习,我们讲解一下各种标识符的含义:

1、准备数据

db.student.insertMany(

    [{

    name:'jack',

    age:22,

    sex:'Man',

    tags:['python','c++','c'],

    grades:[22,33,44,55],

    school:{

    name:'shida',

    city:'xuzhou'

    }

    },{

    name:'jhon',

    age:33,

    sex:null,

    tags:['python','java'],

    grades:[66,22,44,88],

    school:{

    name:'kuangda',

    city:'xuzhou'

    }

    },

    {

    name:'xiaoming',

    age:33,

    tags:['python','java'],

    grades:[66,22,44,88],

    school:{

    name:'kuangda',

    city:'xuzhou'

    }

    }

    ]

)

我们插入3studen他的数据

2、下面找出满足namejack的数据,并且只输出name,age

(这里的_id是默认输出的,其他的字段如果不想输出将将它设置为0,想要输出那个字段将它设置为1

db.student.find({name:'jack'},{name:1,age:1})


3、下面查询年龄在20-30之间的信息

db.student.find({

age:{$gt:20,$lt:30}  

})


4、查询年龄不等于22岁的信息

db.student.find({age:{$ne:22}})

$ne  not equal的缩写,意思是说不等于


5、查询所有人grades数组中的前两个数

db.student.find({},{grades:{$slice:2},name:1,age:1,'school.name':1});

$slice操作符控制查询返回的数组中元素的个数

语法:db.collection.find( { field: value }, { array: {$slice: count }});


6、查询所有人grades数组中的后三个以及姓名

db.student.find({},{grades:{$slice:-3},name:1});



7、查询所有的grades数组中第二个和第三个的人

db.student.find({},{grades:{$slice:[1,2]},name:1})

其中的$slice中第一个参数代表跳过的数目 , 第二个代表返回的数目

8、查询所有文档中不包含sex的

db.student.find({sex:{$exists:false}})

这里我们使用了$exists , 这个字段为true代表包含这个字段的文档,flase代表不包含这个字段的文档

9、查找age等于22或者age等于33的值

db.student.find({$or:[{age:22},{age:33}]})

$or  代表至少满足其中一个的

10、查找出年龄为22或者33并且姓名为jack的人的信息

db.student.find({name:'jack',$or:[{age:33},{age:22}]})

11、查找年龄在20--30岁之间的信息

db.student.find({$and:[{age:{$gt:20}},{age:{$lt:30}}]})

$and是一个短路操作,表示并且


12、查找年龄是22或者30岁的信息

db.student.find({grades:{$in:[22,33]}})

$in和SQL中的in操作很类似,表示其中任意的一个

13、查询出grades中不存在100或者44的文档

db.student.find({} , {grades:{$nin:[100,44]},name:1})

$nin  表示不存在

14、查询年龄不大于30的信息

db.student.find({age:{$not:{$gt:30}}})

其中的$not操作符不能独立使用,必须跟其他操作一起使用,表示不

猜你喜欢

转载自blog.csdn.net/qq_18769269/article/details/80334605