MongoDB基础

来源:互联网 发布:淘宝司法拍卖网首页 编辑:程序博客网 时间:2024/05/18 10:12

第一章 MongoDB介绍

NoSQL介绍

一、NoSQL简介

NoSQL,全称是”Not Only Sql”,指的是非关系型的数据库。

非关系型数据库主要有这些特点:非关系型的、分布式的、开源的、水平可扩展的

原始的目的是为了大规模 web 应用,这场全 新的数据库革命运动早期就有人提出,发展至 2009 年趋势越发高涨。

NoSQL 的拥护者们提倡运用非关系型的数据存储,通常的应用如:模式自由、支持简易复制、简单的 API、最终 的一致性(非 ACID)、大容量数据等。

NoSQL 被我们用得最多的当数 key-value 存储(如Redis),当然还 有其他的文档型的、列存储、图型数据库、xml 数据库等。 

二、引入一个问题为什么会有NoSQL

通用关系数据库功能强大,遵循SQL标准,而且性能卓越而且稳定为什么会出现NoSQL呢?

上面也说过了NoSQL的初识是随着WEB应用的飞速发展中出现的,在期间遇到了一些关系型数据库难以克服的问题,例如:

1、Highperformance- 对数据库高并发读写的需求
web2.0 网站要根据用户个性化信息来实时生成动态页面和提供动态信息,所以基本上无法 使用动态页面静态化技术,因此数据库并发负载非常高,往往要达到每秒上万次读写请求。 关系型数据库应付上万次 SQL 查询还勉强顶得住,但是应付上万次 SQL 写数据请求,硬盘 IO 就已经无法承受了,其实对于普通的 BBS 网站,往往也存在对高并发写请求的需求。
2、HugeStorage- 对海量数据的高效率存储和访问的需求
对于大型的 SNS 网站,每天用户产生海量的用户动态信息,以国外的 Friend feed 为例,一 个月就达到了 2.5 亿条用户动态,对于关系数据库来说,在一张 2.5 亿条记录的表里面进行 SQL 查询,效率是极其低下乃至不可忍受的。再例如大型 web 网站的用户登录系统,例如腾 讯,盛大,动辄数以亿计的帐号,关系数据库也很难应付。
3、HighScalability&&HighAvailability- 对数据库的高可扩展性和高可用性的需求
随着数据库的不断增加,你的数据库没有办法向webserver或app那样简单的通过增加硬件来提升性能和负载能力。并且mysql没有提供水平拆分的和扩容的方案,这是非常头疼的一件事情。

对于上面的三高要求来说很多关系型数据库就遇到了难以克服的问题,并且在WEB2.0的网站和应用来说关系型数据库很多主要特性却无用武之地!!!

1、数据库事务一致性需求

很多 web 实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一 致性要求也不高。因此数据库事务管理成了数据库高负载下一个沉重的负担。

2、数据库的写实时性和读实时性需求

对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于 很多 web 应用来说,并不要求这么高的实时性。

3、对复杂的 SQL 查询,特是多表关联查询的需求

任何大数据量的 web 系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的复杂 SQL查询,特是SNS类型的网站,从需求以及产品设计角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL 的功能被 极大的弱化了。因此,关系数据库在这些越来越多的应用场景下显得不那么合适了

为了解决如上问题NoSQL就诞生了~

三、NoSQL特点

1、它可以处理超大量的数据
2、它运行在便宜的服务器集群上集群扩充起来非常方便并且成本很低。
3、它击碎了性能瓶颈
NoSQL 的支持者称,通过 NoSQL 架构可以省去将 Web 或 Java 应用和数据转换成 SQL 格式的 时间,执行速度变得更快。
“SQL 并非适用于所有的程序代码”,对于那些繁重的重复操作的数据,SQL 值得花钱。但 是当数据库结构非常简单时,SQL 可能没有太大用处。
4、它没有过多的操作
虽然NoSQL的支持者也承认关系型数据库提供了无可比拟的功能集合,而且在数据完整性上也发挥绝对稳定,他们同时也表示,企业的具体需求可能没有那么复杂。
5、 它的支持者源于社区
因为NoSQL项目都是开源的,因此它们缺乏供应商提供的正式支持。这一点它们与大多数 开源项目一样,不得不从社区中寻求支持。
NoSQL 发展至今,出现了好几种非关系性数据库,比如我正在学习的MongoDB

初识MongoDB

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的
他支持的数据结构非常松散,是类似 json 的 bjson 格式,因此可以存储比较复杂的数据类型。
MongoDB最大的特点:它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能, 而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。

1、 面向集合(Collenction-Orented)
意思是数据被分组存储在数据集中, 被称为一个集合(Collenction)。每个集合在数据库中 都有一个唯一的标识名,并且可以包 无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。

2、 模式自由(schema-free)
意味着对于存储在 MongoDB 数据库中的文件,我们不需要知道它的任何结构定义。提了这 么多次"无模式"或"模式自由",它到是个什么概念呢?例如,下面两个记录可以存在于同一个集合里面:
{"welcome" : "Beijing"}
{"age" : 28}

3、 文档型 意思是我们存储的数据是键-值对的集合,键是字符串,值可以是数据类型集合里的任意类型,

包括数组和文档. 我们把这个数据格式称作 “BSON” 即 “Binary Serialized dOcument Notation.”

二、MongoDB特点

  1. 面向集合存储,易于存储对象类型的数据
  2. 模式自由
  3. 支持动态查询
  4. 支持完全索引,包 内部对象
  5. 支持查询
  6. 支持复制和故障恢复
  7. 使用高效的二进制数据存储,包括大型对象(如视频等)
  8. 自动处理碎片,以支持云计算层次的扩展性
  9. 支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl更多请看社区
  10. 文件存储格式为 BSON(一种 JSON 的扩展)
  11. 可通过网络访问

三、MongoDB功能

  1. 面向集合的存储:适合存储对象及 JSON 形式的数据
  2. 动态查询:MongoDB 支持丰富的查询表达式。查询指令使用 JSON 形式的标记,可轻易查询文档中内嵌的对象及数组
  3. 完整的索引支持:包括文档内嵌对象及数组。MongoDB 的查询优化器会分析查询表达式,并生成一个高效的查询计划
  4. 查询监视:MongoDB 包 一系列监视工具用于分析数据库操作的性能
  5. 复制及自动故障转移:MongoDB 数据库支持服务器之间的数据复制,支持主-从模式及
  6. 服务器之间的相互复制。复制的主要目标是提供冗余及自动故障转移
  7. 高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)
  8. 自动分片以支持云级 的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器

四、适用场景

  1. 网站数据:MongoDB 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性
  2. 缓存:由于性能很高,MongoDB 也适合作为信息基础设施的缓存层。在系统重启之后, 由 MongoDB 搭建的持久化缓存层可以避免下层的数据源过载
  3. 大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储
  4. 高伸缩性的场景:MongoDB 非常适合由数十或数百台服务器组成的数据库。MongoDB的路线图中已经包 对 MapReduce 引擎的内置支持
  5. 用于对象及 JSON 数据的存储:MongoDB 的 BSON 数据格式非常适合文档化格式的存储及查询

MongoDB部署与维护入门

一、安装MongoDB

MongoDB维护者还事相当的人性化的给我们提供了YUM源安装就相当的方便了,当然也可以通过源码去安装!

1、创建一个/etc/yum.repos.d/mongodb-enterprise.repo配置文件

内容如下

3.2版本

[mongodb-enterprise]name=MongoDB Enterprise Repositorybaseurl=https://repo.mongodb.com/yum/redhat/$releasever/mongodb-enterprise/stable/$basearch/gpgcheck=1enabled=1gpgkey=https://www.mongodb.org/static/pgp/server-3.2.asc

2.6版本

[mongodb-org-2.6]name=MongoDB 2.6 Repositorybaseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/gpgcheck=0enabled=1

2、执行安装命令

yum install -y mongodb-enterprise

如果你想安装特殊的指定版本可以按照如下命令操作

yum install -y mongodb-enterprise-3.2.1 mongodb-enterprise-server-3.2.1 mongodb-enterprise-shell-3.2.1 mongodb-enterprise-mongos-3.2.1 mongodb-enterprise-tools-3.2.1

3、卸载MongoDB

停止服务

sudo service mongod stop

删除包

sudo yum erase $(rpm -qa | grep mongodb-enterprise)

删除库文件

sudo rm -r /var/log/mongodbsudo rm -r /var/lib/mongo

二、源码安装MongoDB

通过MongoDB官网就可以打开下载地址:https://www.mongodb.com/download-center?jmp=nav&_ga=1.114046535.1911966133.1464573239#community 从里面获取到下载地址之后直接在服务器上下载即可!

1、下载源码

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.2.6.tgz

2、解压

tar -zxvf mongodb-linux-x86_64-rhel62-3.2.6.tgz

解压后的目录:

GNU-AGPL-3.0  #GNU协议文件MPL-2  #MPL协议文件README #README软件提供类似于软件须知THIRD-PARTY-NOTICES  #第三方的提文件bin #主程序目录

上面的几个文件,没有具体的实际作用我们可以删除掉!但是README还是建议保留下的

并且为了方便管理我把的目录名更改为:

mv mongodb-linux-x86_64-rhel62-3.2.6 mongodb

3、启动Mongodb

进入到bin目录下,执行./mongod 看看提示

2016-05-30T10:36:33.520+0800 I STORAGE  [initandlisten] exception in initAndListen: 29 Data directory /data/db not found., terminating

所以在MongoDB在启动的时候默认指定的数据库目录是/data/db我们可以通过 --dbpath=目录名称 来指定数据库默认存储的路径

我们来创建别名和目录指定并启动它

./mongod --dbpath=/work/app/mongodb/data/

现在启动的时候是在前台启动的,如果当前终端退出后那么程序就会退出,怎么让他在后台启动呢? --fork --logpath=日志文件和路径,在使用fork参数的时候必须指定日志文件路径

./mongod --dbpath=/work/app/mongodb/data/ --fork      BadValue: --fork has to be used with --logpath or --syslogtry './mongod --help' for more information

所以后台启动为

./mongod --dbpath=/work/app/mongodb/data/ --fork --logpath=/work/app/mongodb/data/mongodb1.logabout to fork child process, waiting until server is ready for connections.forked process: 16975child process started successfully, parent exiting

关闭程序,在关闭的时候必须执行dbpath

./mongod --dbpath=/work/app/mongodb/data/ --shutdown

4、改为配置文件启动方式

现在我们可以在后台启动了,但是有个问题,我们以后再配置管理的时候,难道每次都要去手动去设置这些参数呢?如果参数错误了造成的问题呢?

4.1、单实例如何通过配置文件启动

首先创建一个目录config目录名称随意,然后在目录里创建一个配置文件

vim mongodb1.cnf

然后在配置文件里写入参数,把咱们平时写的参数写到配置文件中

参考命令行下的命令:

./mongod --dbpath=/work/app/mongodb/data/ --fork --logpath=/work/app/mongodb/data/mongodb1.log

配置文件内容如下:

复制代码
vim mongodb1.cnf#if have a parameter must be write like :  key=valuedbpath=/work/app/mongodb/data/#if not paramenter and you want enable must be write like : fork=truefork=trueport=27017logpath=/work/app/mongodb/data/mongodb1.log
复制代码

启动命令:

./bin/mongod -f config/mongodb1.cnf about to fork child process, waiting until server is ready for connections.forked process: 17220child process started successfully, parent exiting

关闭命令:  因为配置文件中已经有数据库的路径了,所以直接通过--shutdown就可以了

./bin/mongod -f config/mongodb1.cnf --shutdown2016-05-30T12:10:12.295+0800 I CONTROL  [main] log file "/work/app/mongodb/data/mongodb1.log" exists; moved to "/work/app/mongodb/data/mongodb1.log.2016-05-30T04-10-12".killing process with pid: 17220

5、在服务器上通过配置文件启动多实例

首先创建第二个实例的数据库存储目录

mkdir /work/app/mongodb/data2

再添加配置文件

复制代码
cd /work/app/mongodb/configvim mongodb2.cnf#if have a parameter must be write like :  key=valuedbpath=/work/app/mongodb/data2/#if not paramenter and you want enable must be write like : fork=truefork=trueport=27018logpath=/work/app/mongodb/data/mongodb2.log
复制代码

启动实例


复制代码
#第一个实例bin/mongod -f config/mongodb1.cnf#第二个实例bin/mongod -f config/mongodb2.cnf'''以后如果还有其他实例按照上面的操作即可'''
复制代码

查看结果:

ps -ef |grep -i mongroot     17737     1  3 15:22 ?        00:00:00 bin/mongod -f config/mongodb1.cnfroot     17758     1  2 15:22 ?        00:00:00 bin/mongod -f config/mongodb2.cnf

6、编写一个将MongoDB Server写成脚本来进行、启动、停止

 

复制代码
#!/bin/bash#---------------------------------------------------------------------# Written by     : luotianshuai# Program        : mongodb_server.sh will help to contrl :start stop restart mongodb# Creation Date  : 2016/5/30# Last Modified  : 2016/5/30#---------------------------------------------------------------------instance=$1action=$2case "$action" in    start)            /work/app/mongodb/bin/mongod -f /work/app/mongodb/config/"$instance".cnf            ;;    'stop')            /work/app/mongodb/bin/mongod -f /work/app/mongodb/config/"$instance".cnf --shutdown            ;;    'restart')            /work/app/mongodb/bin/mongod -f /work/app/mongodb/config/"$instance".cnf --shutdown            /work/app/mongodb/bin/mongod -f /work/app/mongodb/config/"$instance".cnf            ;;    *)            echo -e "\033[31;40myou must input like : ./mongodb_server.sh mongodbname for example :  ./mongodb_server.sh mongodb1\033[0m"            ;;esac
复制代码

第二章  MongoDB存储结构

基本的操作

一、常用的命令和基础知识

1、进入MongoDB shell

首先我们进入到MongoDB所在目录执行

cd /work/app/mongodb/bin/#启动./mongo

为了方便执行我们可以,这样直接在终端输入mongo调用就可以了

alias mongo='/work/app/mongodb/bin/mongo'

如果想永久生效,把他加入到/etc/profile中即可
2、查看数据库命令

复制代码
#可以通过show dbs;  或者 和Mysql一样执行show databases;> show dbs;local  0.000GB> show databases;local  0.000GB> 
复制代码

3、打开数据库

和关系型数据库中打开数据库是一样的

#使用数据库使用use dbs即可,进入后可以使用showtables;去查看数据库中的表> use dbs;switched to db dbs> show tables;> 

从上面可以看出,一个MongoDB实例是由一个或多个数据库组成的

但是这里需要注意:

在Mysql中的表中,我们给里面的每行叫做‘记录’,但是在MongoDB中我们给每行数据叫做‘文档’

所以在MongoDB中我们给每个表叫做‘集合’。集合中就是存储了文档的集合。

查看当前数据库中的集合命令为:

show collections;

所以:show tables; 和 show databases;命令只是兼容关系型数据库而已,因此他们之间的层次关系就明白了,NICE~

总结:

1、MongoDB逻辑概念总结

文档:文档(Document)是MongodDB中的核心概念,他是MongoDB逻辑存储的最小基本单元

集合:多个文档组成的集合

数据库:多个集合组成的数据库

MongoDb关系型数据库Mysql文档(document)行(row)集合(collections)表(table)数据库(databases)数据库(databases)

 

 

 

 

2、MongoDB 物理存储总结

2.1 命名空间文件:命名空间(.ns结尾文件) 它存储了分配和正在使用的磁盘空间

2.2 数据库文件:以(0,1,2,3...)结尾的,并且后面的文件大小是前面一个文件大小的2倍!

为什么MongodDB物理存储使用这种方式设计呢?好处是什么?:当一方面如果数据库很小的时候,不至于数据库小而浪费存储空间,另外一方面如果数据库增长比较快,通过预分配的方式,是上一个文件的两倍的办法,来避免数据的剧增造成分配文件造成的性能下降,来预分配空间,以空间的办法来换取性能的提升。

2.3 日志文件

    系统日志文件logpath    oplog复制操作日志文件 #只有在主从复制开启之后才会出现    慢查询日志  #需要开启后才可以

慢查询日志通过help就可以看到如何启用

  #这两个参数需要组合使用 --slowms 大于多少秒才算慢查询   --slowms arg (=100)                   value of slow for profile and console                                         log  #默认是关闭的1为慢查询,all为所有的都日志  --profile arg                         0=off 1=slow, 2=all

我们可以通过配置文件进行设置:

profile=1#生产中这里应该大于200毫秒,并且这个必须根据生产中实际的需求来定义的slowms=1

MongoDB数据类型

MongodDB的数据类型是:BSON的数据类型

BSON是Binary JSON是二进制的格式,能将MongoDB的所有文档表示为字节字符串!

JSON:是一种轻量级的数据交换格式。它基于JavaScript的一个子集!

一、在初识MongoDB的时候了解“帮助”

1、最高的帮助

在MongoDB shell中输入help

复制代码
> help        db.help()                    help on db methods        db.mycoll.help()             help on collection methods        sh.help()                    sharding helpers        rs.help()                    replica set helpers        help admin                   administrative help        help connect                 connecting to a db help        help keys                    key shortcuts        help misc                    misc things to know        help mr                      mapreduce        show dbs                     show database names        show collections             show collections in current database        show users                   show users in current database        show profile                 show most recent system.profile entries with time >= 1ms        show logs                    show the accessible logger names        show log [name]              prints out the last segment of log in memory, 'global' is default        use <db_name>                set current database        db.foo.find()                list objects in collection foo        db.foo.find( { a : 1 } )     list objects in foo where a == 1        it                           result of the last line evaluated; use to further iterate        DBQuery.shellBatchSize = x   set default number of items to display on shell        exit                         quit the mongo shell> 
复制代码

2、打开数据库在数据库中查看帮助

进入到数据库中后我们可以使用db.help()查看数据库级别的帮助

db.help()  #查看数据库级别的帮助,里面会显示数据库级别的帮助

3、查看集合中的帮助

> show dbs;local  0.000GBtim    0.000GB> show collections;users> db.users.help()

二、创建数据库

查看当前的数据库

> show dbs;local  0.000GBtim    0.000GB

可以看到当前只有tim和系统自带的local数据库,我们通过use 去打开一个数据库!shuai并且查看数据库

> use shuai;switched to db shuai> show dbs;local  0.000GBtim    0.000GB> 

发现数据库并没有添加,当我们在给数据库中的集合插入一条文档的时候就会:自动创建一条文档合、一个集合、一个数据库。

复制代码
> db.users.insert({"uid":1})WriteResult({ "nInserted" : 1 })> #这个时候看下是否添加了数据库和集合!!!> show dbs;local  0.000GBshuai  0.000GBtim    0.000GB#当前数据库"shuai"下的集合> show collections;users> 
复制代码

2、插入一条数据

复制代码
> db.users.insert({"uid":2,"uname":"luotianshuai","isvip":true,"sex":null,"favorite":["apple","banana",1,2,3,4,5],"regtime":new Date()})WriteResult({ "nInserted" : 1 })> db.users.find(){ "_id" : ObjectId("5754f1ea4b7f62c4992c4ef4"), "uid" : 1 }{ "_id" : ObjectId("5754f2c84b7f62c4992c4ef5"), "uid" : 2, "uname" : "luotianshuai", "isvip" : true, "sex" : null, "favorite" : [ "apple", "banana", 1, 2, 3, 4, 5 ], "regtime" : ISODate("2016-06-06T03:49:28.946Z") }
复制代码

注:这里的数据类型,列表、字典,这里的new Date()是MongoDB就类似Django Model的时间选项类似于:date = models.DateTimeField(auto_now=True)

3、查询数据

查询一条数据

复制代码
> db.users.findOne({"uid":2}){        "_id" : ObjectId("5754f2c84b7f62c4992c4ef5"),        "uid" : 2,        "uname" : "luotianshuai",        "isvip" : true,        "sex" : null,        "favorite" : [                "apple",                "banana",                1,                2,                3,                4,                5        ],        "regtime" : ISODate("2016-06-06T03:49:28.946Z")}> 
复制代码

并且我们可以吧取出来的数据保存在一个变量中,并且通过变量去调用其值

复制代码
> a = db.users.findOne({"uid":2}){        "_id" : ObjectId("5754f2c84b7f62c4992c4ef5"),        "uid" : 2,        "uname" : "luotianshuai",        "isvip" : true,        "sex" : null,        "favorite" : [                "apple",                "banana",                1,                2,                3,                4,                5        ],        "regtime" : ISODate("2016-06-06T03:49:28.946Z")}#并且可以通过变量去调用里面的值> a.a._id                    a.favorite               a.isvip                  a.regtime                a.toLocaleString(        a.uid                    a.valueOf(a.constructor            a.hasOwnProperty(        a.propertyIsEnumerable(  a.sex                    a.toString(              a.uname> a.
复制代码

 三、MongoDB中的数据类型和Mysql数据类型对比

复制代码
> db.users.insert({"uid":3,"salary":312402039840981098098309,"a":1.2423412314223423413})WriteResult({ "nInserted" : 1 })> b = db.users.findOne({"uid":3}){        "_id" : ObjectId("5754f7214b7f62c4992c4ef6"),        "uid" : 3,        "salary" : 3.124020398409811e+23,        "a" : 1.2423412314223423}
复制代码

1、MongoDB中的数字类型和Mysql中的数字类型对比

查看MongoDB中的数字类型他们都是number类型的

复制代码
> typeof(b.uid)number> typeof(b.salary)number> typeof(b.a)number> 
复制代码

可以看出在MongoDB中所有的数字类型都是数值类型的,我们比较下Mysql中的数字类型!

在Mysql中类似“uid":3 这个3应该属于普通的整数,或者是短整形

类似薪水:salary 应该是长整型

类似a应该是双精度浮点型

数字:

在Mysql中对数字类型分的非常详细,有短整形、长整型,浮点数分为单精度和双精度浮点型,而在MongoDB都是64位的浮点数!这样的好处就是很简单,他不需要区分数字类型,就是number类型,简单、简洁。容易理解和在处理的时候也方便。

字符串:

在Mysql中分为定长、变长字符串,无论是定长字符串或者变长字符串,都要对长度事先定义!但是MongoDB中无需事先定义,对长度没有并且的定义并且他甚至可以存储一篇文章!也表现的简单、简洁、

布尔型:

布尔值只有:真、假分别用:True  False  表示

null值:

复制代码
> db.users.find({"sex":null}){ "_id" : ObjectId("5754f1ea4b7f62c4992c4ef4"), "uid" : 1 }{ "_id" : ObjectId("5754f2c84b7f62c4992c4ef5"), "uid" : 2, "uname" : "luotianshuai", "isvip" : true, "sex" : null, "favorite" : [ "apple", "banana", 1, 2, 3, 4, 5 ], "regtime" : ISODate("2016-06-06T03:49:28.946Z") }{ "_id" : ObjectId("5754f7214b7f62c4992c4ef6"), "uid" : 3, "salary" : 3.124020398409811e+23, "a" : 1.2423412314223423 }> 
复制代码

咱们查询以”sex“ 为null条件,但是查询出了3条结果可以得出:

在MongoDB中,1、null代表着值为null   2、者字段不存在。

那么怎么把字段存在并且为null值得文档查找出来呢?

> db.users.find({"sex":null,"sex":{"$exists":true}}){ "_id" : ObjectId("5754f2c84b7f62c4992c4ef5"), "uid" : 2, "uname" : "luotianshuai", "isvip" : true, "sex" : null, "favorite" : [ "apple", "banana", 1, 2, 3, 4, 5 ], "regtime" : ISODate("2016-06-06T03:49:28.946Z") }> #我们查找sex为null的并且给其加一个条件    值存在{"$exists":true}

数组:

一组数据集合

对象类型:

比如日期类型,日期类型是通过对象类型产生的,但是处理日期比较麻烦!这个也是MongoDB的问题表现力不足

 

BSON的特点:优点:简单、简洁、容易理解、解析方便、记忆

缺点:表现力不足比如日期格式(处理起来就比较麻烦)

四、命名规则

1、文档的键名命名几乎所有utf8字符串,只有以下少数例外

  1. $开头
  2. \0   空字符串
  3. _下划线开头,可以用但是不建议使用,凡是系统生成的都是以_开头命名的,所以在实际生产中我们不使用_开头的!

2、集合的命名几乎所有的utf8字符串,只有以下少数例外

  1. $开头
  2. \0   空字符串
  3. system.开头
  4. ”“空字符串

 3、数据库的命名几乎所有的utf8字符串,只有以下少数例外

  1. $开头
  2. \0   空字符串
  3. system.开头
  4. ”“空字符串
  5. /
  6. \

并且这里需要注意:数据库名是不区分大小写的,如果你有一个shuai的数据库,你在创建一个SHUAI的数据库插入数据的时候就会报错,我们一般创建数据库的时候都把MongoDB的数据库名为小写。



第三章 MongoDB基本操作

MongoDB的基本操作包括文档的创建、删除、和更新

文档插入

1、插入

复制代码
#查看当前都有哪些数据库> show dbs;local  0.000GBtim    0.000GB#使用 tim数据库> use tim;switched to db tim#查看都有哪些集合> show collections;user> db.user.indb.user.initializeOrderedBulkOp(    db.user.insert(                     db.user.insertOne(db.user.initializeUnorderedBulkOp(  db.user.insertMany(#使用insert方法插入文档,以{}包注,文档是以键值对出现的,必须成对设置> db.user.insert({"uid":1,"name":"luotianshuai","age":18,"salary":1})WriteResult({ "nInserted" : 1 })> 
复制代码

2、查询

#通过find()方法进行查询> db.user.find(){ "_id" : ObjectId("575f039f0c73a5a96e8f7c8f"), "uid" : 1, "name" : "luotianshuai", "age" : 18, "salary" : 1 }> 

3、如何快速构造1万条文档呢?

可以通过json的循环来实现

复制代码
> for(i=2;i<=20;i++){... db.user.insert({"uid":i,"name":"luotianshuai"+i,"salary":2000+Math.round(Math.random())*5000})... }WriteResult({ "nInserted" : 1 })> 
复制代码

总结:

插入一条文档使用insert方法

文档的规则是键值对,他们是成对出现的他们之间用逗号分隔,键和值通过冒号分隔。

删除文档

1、查询所有

#db.user.find() 如果括号内不加任何条件那么默认是显示所有的文档

2、查询条件

> db.user.find({"uid":1}) #这里指定条件{ "_id" : ObjectId("575f039f0c73a5a96e8f7c8f"), "uid" : 1, "name" : "luotianshuai", "age" : 18, "salary" : 1 }

3、删除文档

> db.user.remove({"uid":1})WriteResult({ "nRemoved" : 1 })  #当removed为1的时候说明删除成功

4、清空集合

> db.user.remove({})WriteResult({ "nRemoved" : 19 })

5、删除集合

> db.user.drop()true  #如果返回true说明删除成功

更新文档

先把之前删除掉饿文档创建一下:

for(i=2;i<=20;i++){ db.user.insert({"uid":i,"name":"luotianshuai"+i,"salary":2000+Math.round(Math.random())*5000}) }

1、更新文档

更新文档这里通过update方法括号内,第一个文档为查询的文档,第二个文档为修改为什么文档!

> db.user.update({"uid":2},{"name":"shuaige"})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

通过查看这种更新方式,后面的文档会覆盖我们要修改文档的整个内容,就变成下面的内容了。uid字段salary字段都被覆盖掉了

> db.user.find(){ "_id" : ObjectId("575f068e0c73a5a96e8f7ca3"), "name" : "shuaige" }

所以用下面的方法可以

复制代码
>  db.user.update({"uid":3},{"uid" : 3, "name" : "shuaige", "salary" : 2000 })WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne({"uid":3}){        "_id" : ObjectId("575f068e0c73a5a96e8f7ca4"),        "uid" : 3,        "name" : "shuaige",        "salary" : 2000}> 
复制代码

可以看到这个更新结果是我们想要的结果,这种方式叫做文档的替换方式更新!

但是我们uid不需要变更,salary也不需要变更但是我们都要写出来!

2、变量替换方式

我们可以把取出来的值赋值给一个变量,然后通过变量去修改!

复制代码
#把查询到的值赋值给a> a = db.user.findOne({"uid":4}){        "_id" : ObjectId("575f068e0c73a5a96e8f7ca5"),        "uid" : 4,        "name" : "luotianshuai4",        "salary" : 7000}> a.nameluotianshuai4#通过变量.字段名去修改字段的内容> a.name="dashuaige"dashuaige> db.user.findOne({"uid":4}){        "_id" : ObjectId("575f068e0c73a5a96e8f7ca5"),        "uid" : 4,        "name" : "luotianshuai4",        "salary" : 7000}#然后在通过update更新> db.user.update({"uid":4},a)WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne({"uid":4}){        "_id" : ObjectId("575f068e0c73a5a96e8f7ca5"),        "uid" : 4,        "name" : "dashuaige",        "salary" : 7000}
复制代码

他的本质还是替换的方式,只不过是方便了

3、使用修改器$inc更新

如何对uid为10的用户增加100块钱工资

复制代码
#这里$inc遵循键值对的规则,他相当于键,要修改的内容为值> db.user.update({"uid":10},{"$inc":{"salary":100}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })#结果{ "_id" : ObjectId("575f068e0c73a5a96e8f7cab"), "uid" : 10, "name" : "luotianshuai10", "salary" : 7100 }#减100> db.user.update({"uid":10},{"$inc":{"salary":-100}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })#结果{ "_id" : ObjectId("575f068e0c73a5a96e8f7cab"), "uid" : 10, "name" : "luotianshuai10", "salary" : 7000 }
复制代码

4、添加一个字段$set修改器

有时候有需求要给某个文档添加一个字段,比如年龄。使用$set

复制代码
#添加器$set> db.user.update({"uid":10},{"$set":{"age":18}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })#结果{ "_id" : ObjectId("575f068e0c73a5a96e8f7cab"), "uid" : 10, "name" : "luotianshuai10", "salary" : 7000, "age" : 18 }
复制代码

5、删除一个字段$unset修改器

有时候有需求要求给某个文档删除一个字段,比如年龄。使用$unset

复制代码
#这里注意使用unset的时候他的值也是一个字典要删除的字段:1 这个1,是true的意思删除它,所以这个1是逻辑的true> db.user.update({"uid":10},{"$unset":{"age":1}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })#结果{ "_id" : ObjectId("575f068e0c73a5a96e8f7cab"), "uid" : 10, "name" : "luotianshuai10", "salary" : 7000 }
复制代码

看上面使用$unset的时候age的值为1说明为true那我们也可以通过值为true来删除它,那么我们来删除uid为10的salary字段

#例子> db.user.update({"uid":10},{"$unset":{"salary":true}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })结果:{ "_id" : ObjectId("575f068e0c73a5a96e8f7cab"), "uid" : 10, "name" : "luotianshuai10" }

6、更新文档的其他参数

复制代码
> db.user.update({arg1},{arg2},arg3,arg4)'''参数1:条件     #通过他来查找参数2:需要操作的更新内容      #把找到的文档修改参数3:参宿4:'''#参数3是做什么呢?咱们看下下面一种情况:如果我现在想更新一条数据uid为100,我这里是没有这个uid为100的文档的> db.user.find({"uid":100}) #为空那么现在我修改他下那么会成功的修改吗?> db.user.update({"uid":100},{"uid":100,"name":"luotianshuai100","salary":100})WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })#看上面的提示找到0,修改0,说明没有更新,那么第3个参数的作用就来了,给他设置为true> db.user.update({"uid":100},{"uid":100,"name":"luotianshuai100","salary":100},true)WriteResult({        "nMatched" : 0,        "nUpserted" : 1, #当查找不到的时候,我们插入它        "nModified" : 0,        "_id" : ObjectId("575f12ee7732f402fffdf61b")})> #查看下,他更新成功了{ "_id" : ObjectId("575f12ee7732f402fffdf61b"), "uid" : 100, "name" : "luotianshuai100", "salary" : 100 }'''so  那么第三个参数的含义就展现出来了,如果查找不到条件,那么就插入我们修改的内容'''#参数4的含义现在有个需求我现在需要给所有的员工加10000块钱,来看下我的操作> db.user.update({},{"$inc":{"salary":1000}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })#可以看到他只更新了匹配到的第一条数据那么,第4个参数的作用就来了> db.user.update({},{"$inc":{"salary":1000}},false,true)WriteResult({ "nMatched" : 20, "nUpserted" : 0, "nModified" : 20 })> '''从上面可以看出,第四个参数的作用就是设置为true的时候就是匹配所有文档'''
复制代码

总结:

第3个和第4个参数默认为false

第一个为查找的条件,第二个为修改内容,第三个是是否在查不到的时候添加修改内容,第四个是是否匹配所有。

更新文档中的文档和更新文档中的数组

用Python理解的话就是字典中的字典和,字典中的列表~~!

先创建一个文档,然后通过修改他来实际看下如何修改文档中的文档和文档中的数组

复制代码
> db.user.insert({"uid":1,"name":"luotianshuai","content":{"addr":"beijing","code":10085,"qq":"1234567"},"email":[]})WriteResult({ "nInserted" : 1 })> db.user.findOne(){        "_id" : ObjectId("575f19c45e4f17980e7b3366"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [ ]}> 
复制代码

一、数组的更新

1、数组增加元素$push

复制代码
> db.user.update({"uid":1},{"$push":{"email":"a"}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne(){        "_id" : ObjectId("575f19c45e4f17980e7b3366"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "a"        ]}> 
复制代码

$push 是在元组中增加一个元素,会在数组的最后追加元素

2、$pushAll 在元组中增加多个元素,但是他不检查元素是否存在

如下:b已经存在了,我再同时增加b,c,d看下是什么结果

复制代码
> db.user.update({"uid":1},{"$push":{"email":"b"}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne(){        "_id" : ObjectId("575f1b9a5e4f17980e7b3367"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "a",                "b"        ]}> 
复制代码

$pushAll

复制代码
> db.user.update({"uid":1},{"$pushAll":{"email":["b","c","d"]}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne(){        "_id" : ObjectId("575f1b9a5e4f17980e7b3367"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "a",                "b",                "b",                "c",                "d"        ]}> 
复制代码

3、$addToSet 往数组中添加一个不重复的元素

> db.user.update({"uid":1},{"$addToSet":{"email":"d"}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })> #从上面的结果可以看出匹配到了一个,插入和修改了0个,说明他可以判断元素是否存在

添加一个元素

#如果不存在就创建> db.user.update({"uid":1},{"$addToSet":{"email":"e"}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> 

添加多个不重复的元素,这时候就得需要用到$eache操作符了

复制代码
#这里e,d都是存在的然后g,f是不存在的批量插入看下结果> db.user.update({"uid":1},{"$addToSet":{"email":{"$each":["e","g","f","d"]}}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })#结果> db.user.findOne(){        "_id" : ObjectId("575f1b9a5e4f17980e7b3367"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "a",                "b",                "b",                "c",                "d",                "e",                "g",                "f"        ]}> 
复制代码

总结:

db.user.update({"uid":1},{"$push":{"email":"a"}})  #在数组末尾添加一个元素

db.user.update({"uid":1},{"$pushAll":{"email":["b","c","d"]}}) #在数组末尾添加多个元素,且并不检查是否重复

db.user.update({"uid":1},{"$addToSet":{"email":"d"}}) #向数组添加一个不重复的元素

#在实际的生产中可能需要插入多个不重复的元素可以使用$addToSet 结合$eache操作符

db.user.update({"uid":1},{"$addToSet":{"email":{"$each":["e","g","f","d"]}}})

二、删除数组元素

1、$pop 从数组中1个值,只能从开头和结尾取值

$pop是从数组中的开头和结尾删除一个值

从上面的结果可以看出,$pop操作符的值中数组的值,为正数的时候从数组的右侧删值,为负数的时候从数组的左侧取值

2、$pull删除指定的数组指定的一个元素

3、$pullAll 删除多个指定的数组元素

总结:

db.user.update({"uid":1},{"$pop":{"email":-1}}) #从左侧删除一个元素

db.user.update({"uid":1},{"$pop":{"email":1}})#从右侧删除一个元素

db.user.update({"uid":1},{"$pull":{"email":"b"}}) #删除数组内的指定一个元素

db.user.update({"uid":1},{"$pullAll":{"email":["b","c"]}}) #删除数组内指定的多个元素

三、数组元素的更新

1、通过变量调用下标修改

复制代码
> db.user.findOne(){        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "d",                "e"        ]}> a = db.user.findOne(){        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "d",                "e"        ]}> a.email[ "d", "e" ]> a.email[0]d> a.email[1]e> a.email[1] = "shuaige.qq.com"shuaige.qq.com> db.user.update({"uid":1},a)WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne(){        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "d",                "shuaige.qq.com"        ]}> 
复制代码

2、通过数组.下标修改

复制代码
> db.user.findOne(){        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "d",                "shuaige.qq.com"        ]}> db.user.update({"uid":1},{"$set":{"email.0":"tim.qq.com"}})WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne(){        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "tim.qq.com",                "shuaige.qq.com"        ]}> 
复制代码

上面的emil.0 相当于emil[0]  通过下标调用mongodb能识别它!

四、文档的文档修改

看下面的例子说明,文档的文档可以通过“.”分法一级一级的嵌套下去修改他如下

1、查询

复制代码
> b = db.user.findOne(){        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 10085,                "qq" : "1234567"        },        "email" : [                "tim.qq.com",                "shuaige.qq.com"        ]}> b.conb.constructor  b.content> b.content{ "addr" : "beijing", "code" : 10085, "qq" : "1234567" }> b.content.addrbeijing> b.content.addr 
复制代码

2、修改

复制代码
> b.content.code = 123456789123456789> b{        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 123456789,                "qq" : "1234567"        },        "email" : [                "tim.qq.com",                "shuaige.qq.com"        ]}> db.user.update({"uid":1},b)WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.findOne(){        "_id" : ObjectId("575f21df5e4f17980e7b3369"),        "uid" : 1,        "name" : "luotianshuai",        "content" : {                "addr" : "beijing",                "code" : 123456789,                "qq" : "1234567"        },        "email" : [                "tim.qq.com",                "shuaige.qq.com"        ]}> 
复制代码





原文地址:http://www.cnblogs.com/luotianshuai/p/5523171.html