MongoDB 教程导读

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

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

让我们一起开始学习MongoDB吧!


MongoDB 的学习列表:


NoSQL 简介

NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL"。

在现代的计算系统上每天网络上都会产生庞大的数据量。

这些数据有很大一部分是由关系数据库管理系统(RDMBSs)来处理。 1970年 E.F.Codd's提出的关系模型的论文 "A relational model of data for large shared data banks",这使得数据建模和应用程序编程更加简单。

通过应用实践证明,关系模型是非常适合于客户服务器编程,远远超出预期的利益,今天它是结构化数据存储在网络和商务应用的主导技术。

NoSQL 是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。

关系型数据库遵循ACID规则

事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:

1、A (Atomicity) 原子性
原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。

比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

2、C (Consistency) 一致性
一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。

3、I (Isolation) 独立性
所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。
比如现有有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。

4、D (Durability) 持久性
持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。


分布式系统

分布式系统(distributed system)由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。

分布式系统是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。

因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。

分布式系统可以应用在在不同的平台上如:Pc、工作站、局域网和广域网上等。


分布式计算的优点

可靠性(容错) :
分布式计算系统中的一个重要的优点是可靠性。一台服务器的系统崩溃并不影响到其余的服务器。

可扩展性:
在分布式计算系统可以根据需要增加更多的机器。

资源共享:
共享数据是必不可少的应用,如银行,预订系统。

灵活性:
由于该系统是非常灵活的,它很容易安装,实施和调试新的服务。

更快的速度:
分布式计算系统可以有多台计算机的计算能力,使得它比其他系统有更快的处理速度。

开放系统:
由于它是开放的系统,本地或者远程都可以访问到该服务。

更高的性能:
相较于集中式计算机网络集群可以提供更高的性能(及更好的性价比)。


分布式计算的缺点

故障排除: :
故障排除和诊断问题。

软件:
更少的软件支持是分布式计算系统的主要缺点。

网络:
网络基础设施的问题,包括:传输问题,高负载,信息丢失等。

安全性:
开发系统的特性让分布式计算系统存在着数据的安全性和共享的风险等问题。


什么是NoSQL?

NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。

NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

为什么使用NoSQL ?

今天我们可以通过第三方平台(如:Google,Facebook等)可以很容易的访问和抓取数据。用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了, NoSQL数据库的发展也却能很好的处理这些大的数据。

web-data-image

实例

社会化关系网:

Each record: UserID1, UserID2
Separate records: UserID, first_name,last_name, age, gender,...
Task: Find all friends of friends of friends of ... friends of a given user.

Wikipedia 页面 :

Large collection of documents
Combination of structured and unstructured data
Task: Retrieve all pages regarding athletics of Summer Olympic before 1950.

RDBMS vs NoSQL

RDBMS
- 高度组织化结构化数据
- 结构化查询语言(SQL) (SQL)
- 数据和关系都存储在单独的表中。
- 数据操纵语言,数据定义语言
- 严格的一致性
- 基础事务

NoSQL
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
-键 - 值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- CAP定理
- 高性能,高可用性和可伸缩性

bigdata

NoSQL 简史

NoSQL一词最早出现于1998年,是Carlo Strozzi开发的一个轻量、开源、不提供SQL功能的关系数据库。

2009年,Last.fm的Johan Oskarsson发起了一次关于分布式开源数据库的讨论[2],来自Rackspace的Eric Evans再次提出了NoSQL的概念,这时的NoSQL主要指非关系型、分布式、不提供ACID的数据库设计模式。

2009年在亚特兰大举行的"no:sql(east)"讨论会是一个里程碑,其口号是"select fun, profit from real_world where relational=false;"。因此,对NoSQL最普遍的解释是"非关联型的",强调Key-Value Stores和文档数据库的优点,而不是单纯的反对RDBMS。


CAP定理(CAP theorem)

在计算机科学中, CAP定理(CAP theorem), 又被称作 布鲁尔定理(Brewer's theorem), 它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性(Consistency) (所有节点在同一时间具有相同的数据)
  • 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
  • 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

  • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
  • CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。
  • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
cap-theoram-image

NoSQL的优点/缺点

优点:

  • - 高可扩展性
  • - 分布式计算
  • - 低成本
  • - 架构的灵活性,半结构化数据
  • - 没有复杂的关系

缺点:

  • - 没有标准化
  • - 有限的查询功能(到目前为止)
  • - 最终一致是不直观的程序

BASE

BASE:Basically Available, Soft-state, Eventually Consistent。 由 Eric Brewer 定义。

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

BASE是NoSQL数据库通常对可用性及一致性的弱要求原则:

  • Basically Availble --基本可用
  • Soft-state --软状态/柔性事务。 "Soft state" 可以理解为"无连接"的, 而 "Hard state" 是"面向连接"的
  • Eventual Consistency --最终一致性 最终一致性, 也是是 ACID 的最终目的。

ACID vs BASE

ACID BASE
原子性(Atomicity) 基本可用(Basically Available)
一致性(Consistency) 软状态/柔性事务(Soft state)
隔离性(Isolation) 最终一致性 (Eventual consistency)
持久性 (Durable)  

NoSQL 数据库分类

类型 部分代表

特点
列存储

Hbase

Cassandra

Hypertable

顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。

文档存储

MongoDB

CouchDB

文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有有机会对某些字段建立索引,实现关系数据库的某些功能。

key-value存储

Tokyo Cabinet / Tyrant

Berkeley DB

MemcacheDB

Redis

可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)

图存储

Neo4J

FlockDB

图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。

对象存储

db4o

Versant

通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。

xml数据库

Berkeley DB XML

BaseX

高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。


谁在使用

现在已经有很多公司使用了NoSQ:
  • Google
  • Facebook
  • Mozilla
  • Adobe
  • Foursquare
  • LinkedIn
  • Digg
  • McGraw-Hill Education
  • Vermont Public Radio

什么是MongoDB ?

MongoDB 是由C++语言编写的开源数据库系统。

在高负载的情况下,添加更多的节点,可以保证服务器性能。

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

mongodb-logo

MongoDB 将数据存储为一个文档。MongoDB是一个基于分布式文件存储的数据库。

FirstName="Arun", Address="St. Xavier's Road", Spouse=[{Name:"Kiran"}], Children=[{Name:"Rihit", Age:8}].
FirstName="Sameer",Address="8 Gandhi Road".

注意:以上数据有两个不同的文档(以"."分隔)。以这种方式存储数据即为文件存储的数据库。 MongoDB是一个面向文档的数据库。



MongoDB的下载

在MongoDB官网下载该安装包,地址为:https://www.mongodb.com/try/download/community


MongoDB的特点

  • 面向集合存储,易存储对象类型的数据。
  • 模式自由
  • 支持动态查询
  • 可通过网络访问
  • 支持查询
  • 支持复制和故障恢复
  • 支持完全索引,包含内部对象
  • 文件存储格式为BSON(一种JSON的扩展)
  • 自动处理碎片,以支持云计算层次的扩展性
  • 使用高效的二进制数据存储,包括大型对象(如视频等)
  • 支持 GolangRUBYPYTHONJAVAC++PHPC# 等多种语言
  • MongoDB安装简单。


MongoDB 的发展历史

  • 2019年08月13日,MongoDB 4.2.0 发布,引入分布式事务
  • 2018年08月06日,MongoDB 4.0.2发布,支持多文档事务
  • 2017年03月17日,MongoDB 3.0.1发布
  • 2013年11月01日,MongoDB 2.4.8 发布
  • 2013年08月20日,MongoDB 2.4.6 发布
  • 2013年04月23日,MongoDB 2.4.3 发布,此版本包括了一些性能优化,功能增强以及bug修复
  • 2012年06月06日,MongoDB 2.0.6 发布,分布式文档数据库
  • 2012年05月23日,MongoDB2.1 开发分支发布了! 该版本采用全新架构,包含诸多增强

MongoDB 的语言支持

MongoDB有官方的驱动如下:



MongoDB 的适用场景

MongoDB 的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)和传统的RDBMS 系统(具有丰富的功能)之间架起一座桥梁,它集两者的优势于一身。根据官方网站的描述,Mongo 适用于以下场景。

  • 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
  • 缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo 搭建的持久化缓存层可以避免下层的数据源过载。
  • 高伸缩性的场景:Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持。
  • 用于对象及JSON 数据的存储:Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。

MongoDB 的使用也会有一些限制,例如,它不适合于以下几个地方。

  • 高度事务性的系统:例如,银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
  • 传统的商业智能应用:针对特定问题的BI 数据库会产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。
  • 需要SQL 的问题。

MongoDB 应用案例

下面列举一些公司MongoDB的实际应用:

  • Craiglist上使用MongoDB的存档数十亿条记录。
  • FourSquare,基于位置的社交网站,在Amazon EC2的服务器上使用MongoDB分享数据。
  • Shutterfly,以互联网为基础的社会和个人出版服务,使用MongoDB的各种持久性数据存储的要求。
  • bit.ly, 一个基于Web的网址缩短服务,使用MongoDB的存储自己的数据。
  • spike.com,一个MTV网络的联营公司, spike.com使用MongoDB的。
  • Intuit公司,一个为小企业和个人的软件和服务提供商,为小型企业使用MongoDB的跟踪用户的数据。
  • sourceforge.net,资源网站查找,创建和发布开源软件免费,使用MongoDB的后端存储。
  • etsy.com ,一个购买和出售手工制作物品网站,使用MongoDB。
  • 纽约时报,领先的在线新闻门户网站之一,使用MongoDB。
  • CERN,著名的粒子物理研究所,欧洲核子研究中心大型强子对撞机的数据使用MongoDB。


MongoDB 下载

MongoDB 提供了可用于 32 位和 64 位系统的预编译二进制包,你可以从 MongoDB 官网下载安装,MongoDB 预编译二进制包下载地址:

https://www.mongodb.com/try/download/community


 注意,这里选择的是zip格式的包,如果选择msi格式的包要遵循msi的安装方式。

解压安装包

下载zip包后,解压安装包,并安装它。

安装过程中,你可以通过点击 "Custom(自定义)" 按钮来设置你的安装目录。

微信截图_20200616125929

微信截图_20200616135051

下一步安装 "install mongoDB compass" 不勾选(当然你也可以选择安装它,可能需要更久的安装时间),MongoDB Compass 是一个图形界面管理工具,我们可以在后面自己到官网下载安装,下载地址:https://www.mongodb.com/download-center/compass

微信截图_20200616135217

创建数据目录

MongoDB 将数据目录存储在 db 目录下。但是这个数据目录不会主动创建,我们在安装完成后需要创建它。请注意,数据目录应该创建在根目录下((如: C: 或者 D: 等 )。

在本教程中,我们已经在 D:盘中解压了 mongodb 文件,现在让我们创建一个 data 的目录然后在 data 目录里创建db目录。

d:>cd d:d:>mkdir datad:>cd datad:data>mkdir dbd:data>cd dbd:datadb>

你也可以通过 window 的资源管理器中创建这些目录,而不一定通过命令行。


命令行下运行 MongoDB 服务器

为了从命令提示符下运行 MongoDB 服务器,你必须从 MongoDB 目录的 bin 目录中执行 mongod.exe 文件。

D://mongodbinmongod --dbpath d:datadb

如果执行成功,会输出如下信息:

2015-09-25T15:54:09.212+0800 I CONTROL  Hotfix KB2731284 or later update is notinstalled, will zero-out data files2015-09-25T15:54:09.229+0800 I JOURNAL  [initandlisten] journal dir=c:datadbjournal2015-09-25T15:54:09.237+0800 I JOURNAL  [initandlisten] recover : no journal files present, no recovery needed2015-09-25T15:54:09.290+0800 I JOURNAL  [durability] Durability thread started2015-09-25T15:54:09.294+0800 I CONTROL  [initandlisten] MongoDB starting : pid=2488 port=27017 dbpath=c:datadb 64-bit host=WIN-1VONBJOCE882015-09-25T15:54:09.296+0800 I CONTROL  [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R22015-09-25T15:54:09.298+0800 I CONTROL  [initandlisten] db version v3.0.6……

连接MongoDB

我们可以在命令窗口中运行 mongo.exe 命令即可连接上 MongoDB,执行如下命令:D:mongodbinmongo.exe

配置 MongoDB 服务

管理员模式打开命令行窗口创建目录,执行下面的语句来创建数据库和日志文件的目录
mkdir D:datadbmkdir D:datalog
创建配置文件创建一个配置文件。该文件必须设置 systemLog.path 参数,包括一些附加的配置选项更好。例如,创建一个配置文件位于 C:mongodbmongod.cfg,其中指定 systemLog.path 和 storage.dbPath。具体配置内容如下:systemLog: destination: file path: D:datalogmongod.logstorage: dbPath: D:datadb

安装 MongoDB服务

通过执行 mongod.exe,使用 --install 选项来安装服务,使用 --config 选项来指定之前创建的配置文件。D:mongodbinmongod.exe --config "D:mongodbmongod.cfg" --install

要使用备用 dbpath,可以在配置文件(例如:C:mongodbmongod.cfg)或命令行中通过 --dbpath 选项指定。

如果需要,您可以安装 mongod.exe 或 mongos.exe 的多个实例的服务。只需要通过使用 --serviceName 和 --serviceDisplayName 指定不同的实例名。只有当存在足够的系统资源和系统的设计需要这么做。

启动 MongoDB 服务

net start MongoDB

关闭 MongoDB 服务

net stop MongoDB

移除 MongoDB 服务

D:mongodbinmongod.exe --remove

MongoDB 后台管理 Shell

如果你需要进入 MongoDB 后台管理,你需要先打开 mongodb 装目录的下的bin目录,然后执行 mongo.exe 文件,MongoDB Shell 是 MongoDB 自带的交互式 Javascript shell,用来对 MongoDB 进行操作和管理的交互式环境。

当你进入 mongoDB 后台后,它默认会链接到 test 文档(数据库):

> mongoMongoDB shell version: 3.0.6connecting to: test……

由于它是一个 JavaScript shell,您可以运行一些简单的算术运算:

> 2 + 24>

db 命令用于查看当前操作的文档(数据库):

> dbtest>

插入一些简单的记录并查找它:

> db.51coolma.insert({x:10})WriteResult({ "nInserted" : 1 })> db.runoob.find(){ "_id" : ObjectId("5604ff74a274a611b0c990aa"), "x" : 10 }>

第一个命令将数字 10 插入到 51coolma 集合的 x 字段中。


Linux平台安装MongoDB


下载

MongoDB提供了linux平台上32位和64位的安装包,你可以在官网下载安装包。

安装前我们需要安装各个 Linux 平台依赖包。

Red Hat/CentOS:

sudo yum install libcurl openssl

Ubuntu 18.04 LTS ("Bionic")/Debian 10 "Buster":

sudo apt-get install libcurl4 openssl

Ubuntu 16.04 LTS ("Xenial")/Debian 9 "Stretch":

sudo apt-get install libcurl3 openssl

MongoDB 源码下载地址:https://www.mongodb.com/try/download/community


0D72BC20-1D77-437E-972C-286EB5EFB183

558D36F2-01AF-49C3-BA07-F2728B216C87

安装

这里我们选择 tgz 下载,下载完安装包,并解压 tgz(以下演示的是 64 位 Linux上的安装) 。

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz    # 下载tar -zxvf mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz                                    # 解压mv mongodb-src-r4.2.8  /usr/local/mongodb4                          # 将解压包拷贝到指定目录

MongoDB 的可执行文件位于 bin 目录下,所以可以将其添加到 PATH 路径中:

export PATH=<mongodb-install-directory>/bin:$PATH

<mongodb-install-directory> 为你 MongoDB 的安装路径。如本文的 /usr/local/mongodb4 。

export PATH=/usr/local/mongodb4/bin:$PATH

创建数据库目录

MongoDB 的数据存储在 data 目录的 db 目录下,但是这个目录在安装过程不会自动创建,所以你需要手动创建 data 目录,并在 data 目录中创建db目录。

以下实例中我们将 data 目录创建于根目录下(/)。

注意:/data/db 是 MongoDB 默认的启动的数据库路径(--dbpath)。

mkdir -p /data/db

命令行中运行 MongoDB 服务

你可以再命令行中执行mongo安装目录中的bin目录执行mongod命令来启动mongdb服务。

注意:如果你的数据库目录不是/data/db,可以通过 --dbpath 来指定。

$ ./mongod2015-09-25T16:39:50.549+0800 I JOURNAL  [initandlisten] journal dir=/data/db/journal2015-09-25T16:39:50.550+0800 I JOURNAL  [initandlisten] recover : no journal files present, no recovery needed2015-09-25T16:39:50.869+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 3.162015-09-25T16:39:51.206+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 3.522015-09-25T16:39:52.775+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 7.7 

MongoDB后台管理 Shell

如果你需要进入MongoDB后台管理,你需要先打开mongodb装目录的下的bin目录,然后执行mongo命令文件。

MongoDB Shell是MongoDB自带的交互式Javascript shell,用来对MongoDB进行操作和管理的交互式环境。

当你进入mongoDB后台后,它默认会链接到 test 文档(数据库):

$ cd /usr/local/mongodb/bin$ ./mongoMongoDB shell version: 3.0.6connecting to: testWelcome to the MongoDB shell.……

由于它是一个JavaScript shell,您可以运行一些简单的算术运算:

> 2+24> 3+69

现在让我们插入一些简单的数据,并对插入的数据进行检索:

> db.W3Cschool.insert({x:10})WriteResult({ "nInserted" : 1 })> db.W3Cschool.find(){ "_id" : ObjectId("5604ff74a274a611b0c990aa"), "x" : 10 }>

第一个命令是将数据 8 插入到w3r集合(表)的 z 字段中。



MongoDb web 用户界面

MongoDB 提供了简单的 HTTP 用户界面。 如果你想启用该功能,需要在启动的时候指定参数 --rest 。

$ ./mongod --dbpath=/data/db --rest

MongoDB 的 Web 界面访问端口比服务的端口多1000。

如果你的MongoDB运行端口使用默认的27017,你可以在端口号为28017访问web用户界面,即地址为:http://localhost:28017。

图注


MongoDB 概念解析

不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下面我们挨个介绍。

下表将帮助您更容易理解Mongo中的一些概念:

SQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段/域
indexindex索引
table joins 表连接,MongoDB不支持
primary keyprimary key主键,MongoDB自动将_id字段设置为主键

通过下图实例,我们也可以更直观的的了解Mongo中的一些概念:


数据库

一个mongodb中可以建立多个数据库。

MongoDB的默认数据库为"db",该数据库存储在data目录中。

MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

"show dbs" 命令可以显示所有数据的列表。

$ ./mongoMongoDB shell version: 3.0.6connecting to: test> show dbslocal  0.078GBtest   0.078GB> 

执行 "db" 命令可以显示当前数据库对象或集合。

$ ./mongoMongoDB shell version: 3.0.6connecting to: test> dbtest> 

运行"use"命令,可以连接到一个指定的数据库。

> use localswitched to db local> dblocal> 

以上实例命令中,"local" 是你要链接的数据库。

在下一个章节我们将详细讲解MongoDB中命令的使用。

数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串。

  • 不能是空字符串("")。
  • 不得含有' '(空格)、.、$、/、和 (空宇符)。
  • 应全部小写。
  • 最多64字节。

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

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

文档

文档是一个键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。

一个简单的文档例子如下:

{"site":"www.51coolma.cn", "name":"W3Cschool教程"}

下表列出了 RDBMS 与 MongoDB 对应的术语:

RDBMSMongoDB
数据库数据库
表格集合
文档
字段
表联合嵌入文档
主键主键 (MongoDB 提供了 key 为 _id )
数据库服务和客户端
Mysqld/Oraclemongod
mysql/sqlplusmongo

需要注意的是:

  1. 文档中的键/值对是有序的。
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB区分类型和大小写。
  4. MongoDB的文档不能有重复的键。
  5. 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

  • 键不能含有 (空字符)。这个字符用来表示键的结尾。
  • .和$有特别的意义,只有在特定环境下才能使用。
  • 以下划线"_"开头的键是保留的(不是严格要求的)。

集合

集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。

集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

比如,我们可以将以下不同数据结构的文档插入到集合中:

{"site":"www.baidu.com"}{"site":"www.google.com","name":"Google"}{"site":"www.51coolma.cn","name":"W3Cschool教程","num":5}

当第一个文档插入时,集合就会被创建。

合法的集合名

  • 集合名不能是空字符串""。
  • 集合名不能含有字符(空字符),这个字符表示集合名的结尾。
  • 集合名不能以"system."开头,这是为系统集合保留的前缀。
  • 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。 

如下实例:

db.col.findOne()

capped collections

Capped collections 就是固定大小的collection。

它有很高的性能以及队列过期的特性(过期按照插入的顺序). 有点和 "RRD" 概念类似。

Capped collections是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能 和标准的collection不同,你必须要显式的创建一个capped collection, 指定一个collection的大小,单位是字节。collection的数据存储空间值提前分配的。

要注意的是指定的存储大小包含了数据库的头信息。

db.createCollection("mycoll", {capped:true, size:100000})
  • 在capped collection中,你能添加新的对象。
  • 能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。
  • 数据库不允许进行删除。使用drop()方法删除collection所有的行。
  • 注意: 删除之后,你必须显式的重新创建这个collection。
  • 在32bit机器中,capped collection最大存储为1e9( 1X109)个字节。

元数据

数据库的信息是存储在集合中。它们使用了系统的命名空间:

dbname.system.*

在MongoDB数据库中名字空间 <dbname>.system.* 是包含多种系统信息的特殊集合(Collection),如下:

集合命名空间描述
dbname.system.namespaces列出所有名字空间。
dbname.system.indexes列出所有索引。
dbname.system.profile包含数据库概要(profile)信息。
dbname.system.users列出所有可访问数据库的用户。
dbname.local.sources包含复制对端(slave)的服务器信息和状态。

对于修改系统集合中的对象有如下限制。

在{{system.indexes}}插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)。

{{system.users}}是可修改的。 {{system.profile}}是可删除的。


MongoDB 数据类型

下表为MongoDB中常用的几种数据类型。

数据类型描述
String字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean布尔值。用于存储布尔值(真/假)。
Double双精度浮点值。用于存储浮点值。
Min/Max keys将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Arrays用于将数组或列表或多个值存储为一个键。
Timestamp时间戳。记录文档修改或添加的具体时间。
Object用于内嵌文档。
Null用于创建空值。
Symbol符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID对象 ID。用于创建文档的 ID。
Binary Data二进制数据。用于存储二进制数据。
Code代码类型。用于在文档中存储 JavaScript 代码。
Regular expression正则表达式类型。用于存储正则表达式。

MongoDB - 连接


描述

在本教程我们将讨论MongoDB的不同连接方式。


启动 MongoDB服务

在前面的教程中,我们已经讨论了如何启动MongoDB服务,你只需要在MongoDB安装目录的bin目录下执行'mongod'即可。

执行启动操作后,mongodb在输出一些必要信息后不会输出任何信息,之后就等待连接的建立,当连接被建立后,就会开始打印日志信息。

你可以使用MongoDB shell 来连接 MongoDB 服务器。你也可以使用PHP来连接mongodb。本教程我们会使用 MongoDB shell来连接Mongodb服务,之后的章节我们将会介绍如何通过php 来连接MongoDB服务。

默认情况下,MongoDB的启动端口为27017。比MongoDB启动端口大1000的端口为MongoDB的web用户界面,你可以再浏览器中输入http://localhost:28017 来访问MongoDB的web用户界面。



通过shell连接MongoDB服务

你可以通过执行以下命令来连接MongoDB的服务。

注意:localhost为主机名,这个选项是必须的:

mongodb://localhost

当你执行以上命令时,你可以看到以下输出结果:

mongodb-connect

如果你检查从哪里连接到MongoDB的服务器,您可以看到如下信息:

mongodb-connected 最后一行(标记处),打印了你成功连接上MongoDB服务的信息。

MongoDB连接命令格式

使用用户名和密码连接到MongoDB服务器,你必须使用 'username:password@hostname/dbname' 格式,'username'为用户名,'password' 为密码。

使用用户名和密码连接登陆到默认数据库:<、p>

mongodb://mongo_admin:AxB6_w3r@localhost/

以上命令中,用户 mongo_admin使用密码AxB6_w3r连接到本地的MongoDB服务上。输出结果如下所示:<、p> mongodb-connect-with-username-and-password-to-default-database

使用用户名和密码连接登陆到指定数据库:

连接到指定数据库的格式如下:

mongodb://mongo_admin:AxB6_w3r@localhost/w3r


更多连接实例

连接本地数据库服务器,端口是默认的。

mongodb://localhost

使用用户名fred,密码foobar登录localhost的admin数据库。

mongodb://fred:foobar@localhost

使用用户名fred,密码foobar登录localhost的baz数据库。

mongodb://fred:foobar@localhost/baz

连接 replica pair, 服务器1为example1.com服务器2为example2。

mongodb://example1.com:27017,example2.com:27017

连接 replica set 三台服务器 (端口 27017, 27018, 和27019):

mongodb://localhost,localhost:27018,localhost:27019

连接 replica set 三台服务器, 写入操作应用在主服务器 并且分布查询到从服务器。

mongodb://host1,host2,host3/?slaveOk=true

直接连接第一个服务器,无论是replica set一部分或者主服务器或者从服务器。

mongodb://host1,host2,host3/?connect=direct;slaveOk=true

当你的连接服务器有优先级,还需要列出所有服务器,你可以使用上述连接方式。

安全模式连接到localhost:

mongodb://localhost/?safe=true

以安全模式连接到replica set,并且等待至少两个复制服务器成功写入,超时时间设置为2秒。

mongodb://host1,host2,host3/?safe=true;w=2;wtimeoutMS=2000


参数选项说明

标准格式:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

标准的连接格式包含了多个选项(options),如下所示:

选项 描述
replicaSet=name 验证replica set的名称。 Impliesconnect=replicaSet.
slaveOk=true|false
  • true:在connect=direct模式下,驱动会连接第一台机器,即使这台服务器不是主。在connect=replicaSet模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器。
  • false: 在 connect=direct模式下,驱动会自动找寻主服务器. 在connect=replicaSet 模式下,驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器。
safe=true|false
    • true: 在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功。(还要参考 wtimeoutMS).
false: 在每次更新之后,驱动不会发送getLastError来确保更新成功。
w=n 驱动添加 { w : n } 到getLastError命令. 应用于safe=true。
wtimeoutMS=ms 驱动添加 { wtimeout : ms } 到 getlasterror 命令. 应用于 safe=true.
fsync=true|false
  • true: 驱动添加 { fsync : true } 到 getlasterror 命令.应用于 safe=true.
  • false: 驱动不会添加到getLastError命令中。
journal=true|false 如果设置wie true, 同步到 journal (在提交到数据库前写入到实体中). 应用于 safe=true
connectTimeoutMS=ms 可以打开连接的时间。
socketTimeoutMS=ms 发送和接受sockets的时间。

MongoDB 创建数据库

语法

MongoDB 创建数据库的语法格式如下:

use DATABASE_NAME

如果数据库不存在,则创建数据库,否则切换到指定数据库。

实例

以下实例我们创建了数据库 youj:

> use youjswitched to db youj> dbyouj> 

如果你想查看所有数据库,可以使用 show dbs 命令:

> show dbslocal  0.078GBtest   0.078GB> 

可以看到,我们刚创建的数据库 youj 并不在数据库的列表中,要显示它,我们需要向 youj 数据库插入一些数据。

> db.youj.insert({"name":"W3Cschool教程"})WriteResult({ "nInserted" : 1 })> show dbslocal   0.078GByouj  0.078GBtest    0.078GB> 

MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中。

MongoDB 删除数据库

语法

MongoDB 删除数据库的语法格式如下:

db.dropDatabase()

删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。

实例

以下实例我们删除了数据库 youj。

首先,查看所有数据库:

> show dbslocal   0.078GByouj  0.078GBtest    0.078GB

接下来我们切换到数据库 youj:

> use youjswitched to db youj> 

执行删除命令:

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

最后,我们再通过 show dbs 命令数据库是否删除成功:

> show dbslocal  0.078GBtest   0.078GB> 

删除集合

集合删除语法格式如下:

db.collection.drop()

MongoDB 插入文档

本章节中我们将向大家介绍如何将数据插入到MongoDB的集合中。

文档的数据结构和JSON基本一样。

所有存储在集合中的数据都是BSON格式。

BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON。

插入文档

MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下:

db.COLLECTION_NAME.insert(document)

实例

以下文档可以存储在 MongoDB 的 51coolma.cn数据库 的 col集合中:

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb', 'database', 'NoSQL'],    likes: 100})

以上实例中 col 是我们的集合名,前一章节我们已经创建过了,如果该集合不在该数据库中, MongoDB 会自动创建该集合并插入文档。

查看已插入文档:

> db.col.find(){ "_id" : ObjectId("56064886ade2f21f36b03134"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }> 

我们也可以将数据定义为一个变量,如下所示:

> document=({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb', 'database', 'NoSQL'],    likes: 100});

执行后显示结果如下:

{        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

执行插入操作:

> db.col.insert(document)WriteResult({ "nInserted" : 1 })> 

插入文档你也可以使用 db.col.save(document) 命令。如果不指定 _id 字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新该 _id 的数据。

MongoDB使用update()函数更新数据


描述

本章节我们将开始学习如何更新MongoDB中的集合数据。

MongoDB数据更新可以使用update()函数。

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

update()函数接受以下四个参数:

  • criteria : update的查询条件,类似sql update查询内where后面的。
  • objNew : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
  • upsert : 这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

在本教程中我们使用的数据库名称为"myinfo",集合名称为"userdetails",以下为插入的数据:

> document=({"user_id" : "MNOPBWN","password" :"MNOPBWN" ,"date_of_join" : "16/10/2010"
,"education" :"M.C.A." , "profession" : "CONSULTANT","interest" : "MUSIC","community_name" :["MODERN MUSIC",
"CLASSICAL MUSIC","WESTERN MUSIC"],"community_moder_id" : ["MR. BBB","MR. JJJ","MR MMM"],"community_members" :
[500,200,1500],"friends_id" : ["MMM123","NNN123","OOO123"],"ban_friends_id" :["BAN123","BAN456","BAN789"]});

> db.userdetails.insert(document)

> document=({"user_id" : "QRSTBWN","password" :"QRSTBWN" ,"date_of_join" : "17/10/2010" ,"education" :"M.B.A."
, "profession" : "MARKETING","interest" : "MUSIC","community_name" :["MODERN MUSIC", "CLASSICAL MUSIC","WESTERN
MUSIC"],"community_moder_id" : ["MR. BBB","MR. JJJ","MR MMM"],"community_members" : [500,200,1500],"friends_id" :
["MMM123","NNN123","OOO123"],"ban_friends_id" :["BAN123","BAN456","BAN789"]});

> db.userdetails.insert(document)

update() 命令

如果我们想将"userdetails"集合中"user_id"为"QRSTBWN"的"password"字段修改为"NEWPASSWORD",那么我们可以使用update()命令来实现(如下实例所示)。

如果criteria参数匹配集合中的任何一条数据,它将会执行替换命令,否则会插入一条新的数据。

以下实例将更新第一条匹配条件的数据:

> db.userdetails.update({"user_id" : "QRSTBWN"},{"user_id" : "QRSTBWN","password" :"NEWPASSWORD"
,"date_of_join" : "17/10/2010" ,"education" :"M.B.A." , "profession" : "MARKETING","interest" :
"MUSIC","community_name" :["MODERN MUSIC", "CLASSICAL MUSIC","WESTERN MUSIC"],"community_moder_id" : ["MR.
BBB","MR. JJJ","MR MMM"],"community_members" : [500,200,1500],"friends_id" : ["MMM123","NNN123","OOO123"],"ban_friends_id" :["BAN123","BAN456","BAN789"]});

update-data-into-mongodb-comand


查看集合中更新后的数据

我们可以使用以下命令查看数据是否更新:

>db.userdetails.find();

update-data-into-mongodb-view


更多实例

只更新第一条记录:

db.test0.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );

全部更新:

db.test0.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );

只添加第一条:

db.test0.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );

全部添加加进去:

db.test0.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );

全部更新:

db.test0.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );

只更新第一条记录:

db.test0.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );

MongoDB 删除文档

在前面的几个章节中我们已经学习了MongoDB中如何为集合添加数据和更新数据。在本章节中我们将继续学习MongoDB集合的删除。

MongoDB remove()函数是用来移除集合中的数据。

MongoDB数据更新可以使用update()函数。在执行remove()函数前先执行find()命令来判断执行的条件是否正确,这是一个比较好的习惯。

语法

remove() 方法的基本语法格式如下所示:

db.collection.remove(   <query>,   <justOne>)

如果你的 MongoDB 是 2.6 版本以后的,语法格式如下:

db.collection.remove(   <query>,   {     justOne: <boolean>,     writeConcern: <document>   })

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档。
  • writeConcern :(可选)抛出异常的级别。

实例

以下文档我们执行两次插入操作:

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb', 'database', 'NoSQL'],    likes: 100})

使用 find() 函数查询数据:

> db.col.find(){ "_id" : ObjectId("56066169ade2f21f36b03137"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }{ "_id" : ObjectId("5606616dade2f21f36b03138"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }

接下来我们移除 title 为 'MongoDB 教程' 的文档:

>db.col.remove({'title':'MongoDB 教程'})WriteResult({ "nRemoved" : 2 })           # 删除了两条数据>db.col.find()……                                        # 没有数据

如果你只想删除第一条找到的记录可以设置 justOne 为 1,如下所示:

>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)

如果你想删除所有数据,可以使用以下方式(类似常规 SQL 的 truncate 命令):

>db.col.remove({})>db.col.find()>

MongoDB 查询文档

语法

MongoDB 查询数据的语法格式如下:

>db.COLLECTION_NAME.find()

find() 方法以非结构化的方式来显示所有文档。

如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:

>db.col.find().pretty()

pretty() 方法以格式化的方式来显示所有文档。

实例

以下实例我们查询了集合 col 中的数据:

> db.col.find().pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

除了 find() 方法之外,还有一个 findOne() 方法,它只返回一个文档。


MongoDB 与 RDBMS Where 语句比较

如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:

操作格式范例RDBMS中的类似语句
等于{<key>:<value>}db.col.find({"by":"51coolma"}).pretty()where by = '51coolma'
小于{<key>:{$lt:<value>}}db.col.find({"likes":{$lt:50}}).pretty()where likes < 50
小于或等于{<key>:{$lte:<value>}}db.col.find({"likes":{$lte:50}}).pretty()where likes <= 50
大于{<key>:{$gt:<value>}}db.col.find({"likes":{$gt:50}}).pretty()where likes > 50
大于或等于{<key>:{$gte:<value>}}db.col.find({"likes":{$gte:50}}).pretty()where likes >= 50
不等于{<key>:{$ne:<value>}}db.col.find({"likes":{$ne:50}}).pretty()where likes != 50

MongoDB AND 条件

MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,及常规 SQL 的 AND 条件。

语法格式如下:

>db.col.find({key1:value1, key2:value2}).pretty()

实例

以下实例通过 by 和 title 键来查询 51coolma 中 MongoDB 教程 的数据

> db.col.find({"by":"51coolma", "title":"MongoDB 教程"}).pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

以上实例中类似于 WHERE 语句:WHERE by='51coolma' AND title='MongoDB 教程'


MongoDB OR 条件

MongoDB OR 条件语句使用了关键字 $or,语法格式如下:

>db.col.find(   {      $or: [	     {key1: value1}, {key2:value2}      ]   }).pretty()

实例

以下实例中,我们演示了查询键 by 值为 51coolma 或键 title 值为 MongoDB 教程 的文档。

>db.col.find({$or:[{"by":"51coolma"},{"title": "MongoDB 教程"}]}).pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}>

AND 和 OR 联合使用

以下实例演示了 AND 和 OR 联合使用,类似常规 SQL 语句为: 'where likes>50 AND (by = '51coolma' OR title = 'MongoDB 教程')'

>db.col.find({"likes": {$gt:50}, $or: [{"by": "51coolma"},{"title": "MongoDB 教程"}]}).pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

MongoDB 条件操作符


描述

条件操作符用于比较两个表达式并从mongoDB集合中获取数据。

在本章节中,我们将讨论如何在MongoDB中使用条件操作符。

MongoDB中条件操作符有:

  • (>) 大于 - $gt
  • (<) 小于 - $lt
  • (>=) 大于等于 - $gte
  • (<= ) 小于等于 - $lte

我们使用的数据库名称为"51coolmadb" 我们的集合名称为"col",以下为我们插入的数据。

为了方便测试,我们可以先使用以下命令清空集合 "col" 的数据:

db.col.remove({})

插入以下数据

>db.col.insert({    title: 'PHP 教程',     description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['php'],    likes: 200})

>db.col.insert({title: 'Java 教程',     description: 'Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['java'],    likes: 150})

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb'],    likes: 100})

使用find()命令查看数据:

> db.col.find(){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB (>) 大于操作符 - $gt

如果你想获取 "col" 集合中 "likes" 大于 100 的数据,你可以使用以下命令:

db.col.find({"likes" : {$gt : 100}})

类似于SQL语句:

Select * from col where likes > 100;

输出结果:

> db.col.find({"likes" : {$gt : 100}}){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }> 

MongoDB(>=)大于等于操作符 - $gte

如果你想获取"col"集合中 "likes" 大于等于 100 的数据,你可以使用以下命令:

db.col.find({likes : {$gte : 100}})

类似于SQL语句:

Select * from col where likes >=100;

输出结果:

> db.col.find({likes : {$gte : 100}}){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }> 

MongoDB (<) 小于操作符 - $lt

如果你想获取"col"集合中 "likes" 小于 150 的数据,你可以使用以下命令:

db.col.find({likes : {$lt : 150}})

类似于SQL语句:

Select * from col where likes < 150;

输出结果:

> db.col.find({likes : {$lt : 150}}){ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB (<=) 小于等于操作符 - $lte

如果你想获取"col"集合中 "likes" 小于等于 150 的数据,你可以使用以下命令:

db.col.find({likes : {$lte : 150}})

类似于SQL语句:

Select * from col where likes <= 150;

输出结果:

> db.col.find({likes : {$lte : 150}}){ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB 使用 (<) 和 (>) 查询 - $lt 和 $gt

如果你想获取"col"集合中 "likes" 大于100,小于 200 的数据,你可以使用以下命令:

db.col.find({likes : {$lt :200, $gt : 100}})

类似于SQL语句:

Select * from col where likes>100 AND  likes<200;

输出结果:

> db.col.find({likes : {$lt :200, $gt : 100}}){ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }> 

MongoDB $type 操作符

描述

在本章节中,我们将继续讨论MongoDB中条件操作符 $type。

$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。

MongoDB 中可以使用的类型如下表所示:

类型数字备注
Double1 
String2 
Object3 
Array4 
Binary data5 
Undefined6已废弃。
Object id7 
Boolean8 
Date9 
Null10 
Regular Expression11 
JavaScript13 
Symbol14 
JavaScript (with scope)15 
32-bit integer16 
Timestamp17 
64-bit integer18 
Min key255Query with -1.
Max key127 

我们使用的数据库名称为"51coolmadb" 我们的集合名称为"col",以下为我们插入的数据。

简单的集合"col":

>db.col.insert({    title: 'PHP 教程',     description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['php'],    likes: 200})

>db.col.insert({title: 'Java 教程',     description: 'Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['java'],    likes: 150})

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb'],    likes: 100})

使用find()命令查看数据:

> db.col.find(){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB 操作符 - $type 实例

如果想获取 "col" 集合中 title 为 String 的数据,你可以使用以下命令:

db.col.find({"title" : {$type : 2}})

输出结果为:

{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB Limit与Skip方法


MongoDB Limit() 方法

如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。

语法

limit()方法基本语法如下所示:

>db.COLLECTION_NAME.find().limit(NUMBER)

实例

集合 myycol 中的数据如下:

{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Tutorials Point Overview"}

以下实例为显示查询文档中的两条记录:

>db.mycol.find({},{"title":1,_id:0}).limit(2){"title":"MongoDB Overview"}{"title":"NoSQL Overview"}>

注:如果你们没有指定limit()方法中的参数则显示集合中的所有数据。


MongoDB Skip() 方法

我们除了可以使用limit()方法来读取指定数量的数据外,还可以使用skip()方法来跳过指定数量的数据,skip方法同样接受一个数字参数作为跳过的记录条数。

语法

skip() 方法脚本语法格式如下:

>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

实例

以上实例只会显示第二条文档数据

>db.mycol.find({},{"title":1,_id:0}).limit(1).skip(1){"title":"NoSQL Overview"}>

注:skip()方法默认参数为 0 。

MongoDB 排序


MongoDB sort()方法

在MongoDB中使用使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而-1是用于降序排列。

语法

sort()方法基本语法如下所示:

>db.COLLECTION_NAME.find().sort({KEY:1})

实例

col 集合中的数据如下:

{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Tutorials Point Overview"}

以下实例演示了 col 集合中的数据按字段 title 的降序排列:

>db.mycol.find({},{"title":1,_id:0}).sort({"title":-1}){"title":"Tutorials Point Overview"}{"title":"NoSQL Overview"}{"title":"MongoDB Overview"}>

注: 如果没有指定sort()方法的排序方式,默认按照文档的升序排列。

MongoDB 索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构


ensureIndex() 方法

MongoDB使用 ensureIndex() 方法来创建索引。

语法

ensureIndex()方法基本语法格式如下所示:

>db.COLLECTION_NAME.ensureIndex({KEY:1})

语法中 Key 值为你要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1即可。

实例

>db.mycol.ensureIndex({"title":1})>

ensureIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。

>db.mycol.ensureIndex({"title":1,"description":-1})>

ensureIndex() 接收可选参数,可选参数列表如下:

ParameterTypeDescription
backgroundBoolean建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false
uniqueBoolean建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
namestring索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDupsBoolean在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparseBoolean对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSecondsinteger指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
vindex version索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weightsdocument索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_languagestring对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_overridestring对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

实例

在后台创建索引:

db.values.ensureIndex({open: 1, close: 1}, {background: true})

通过在创建索引时加background:true 的选项,让创建工作在后台执行

MongoDB 聚合

MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。


aggregate() 方法

MongoDB中聚合的方法使用aggregate()。

语法

aggregate() 方法的基本语法格式如下所示:

>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

实例

集合中的数据如下:

{   _id: ObjectId(7df78ad8902c)   title: 'MongoDB Overview',    description: 'MongoDB is no sql database',   by_user: '51coolma.cn',   url: 'http://www.51coolma.cn',   tags: ['mongodb', 'database', 'NoSQL'],   likes: 100},{   _id: ObjectId(7df78ad8902d)   title: 'NoSQL Overview',    description: 'No sql database is very fast',   by_user: '51coolma.cn',   url: 'http://www.51coolma.cn',   tags: ['mongodb', 'database', 'NoSQL'],   likes: 10},{   _id: ObjectId(7df78ad8902e)   title: 'Neo4j Overview',    description: 'Neo4j is no sql database',   by_user: 'Neo4j',   url: 'http://www.neo4j.com',   tags: ['neo4j', 'database', 'NoSQL'],   likes: 750},

现在我们通过以上集合计算每个作者所写的文章数,使用aggregate()计算结果如下:

> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}]){   "result" : [      {         "_id" : "51coolma.cn",         "num_tutorial" : 2      },      {         "_id" : "Neo4j",         "num_tutorial" : 1      }   ],   "ok" : 1}>

以上实例类似sql语句: select by_user, count(*) from mycol group by by_user

在上面的例子中,我们通过字段by_user字段对数据进行分组,并计算by_user字段相同值的总和。

下表展示了一些聚合的表达式:

表达式描述实例
$sum计算总和。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg计算平均值db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min获取集合中所有文档对应值得最小值。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max获取集合中所有文档对应值得最大值。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push在结果文档中插入值到一个数组中。db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet在结果文档中插入值到一个数组中,但不创建副本。db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first根据资源文档的排序获取第一个文档数据。db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last根据资源文档的排序获取最后一个文档数据db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

管道的概念

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。

MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。

表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。

这里我们介绍一下聚合框架中常用的几个操作:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

管道操作符实例

1、$project实例

db.article.aggregate(    { $project : {        title : 1 ,        author : 1 ,    }} );

这样的话结果中就只还有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样:

db.article.aggregate(    { $project : {        _id : 0 ,        title : 1 ,        author : 1    }});

2.$match实例

db.articles.aggregate( [                        { $match : { score : { $gt : 70, $lte : 90 } } },                        { $group: { _id: null, count: { $sum: 1 } } }                       ] );

$match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。

3.$skip实例

db.article.aggregate(    { $skip : 5 });

经过$skip管道操作符处理后,前五个文档被"过滤"掉。

MongoDB 复制(副本集)

MongoDB复制是将数据同步在多个服务器的过程。

复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。

复制还允许您从硬件故障和服务中断中恢复数据。


什么是复制?

  • 保障数据的安全性
  • 数据高可用性 (24*7)
  • 灾难恢复
  • 无需停机维护(如备份,重建索引,压缩)
  • 分布式读取数据

MongoDB复制原理

mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。

mongodb各个节点常见的搭配方式为:一主一从、一主多从。

主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

MongoDB复制结构图如下所示:

MongoDB复制结构图

以上结构图总,客户端总主节点读取数据,在客户端写入数据到主节点是, 主节点与从节点进行数据交互保障数据的一致性。

副本集特征:

  • N 个节点的集群
  • 任何节点可作为主节点
  • 所有写入操作都在主节点上
  • 自动故障转移
  • 自动恢复

MongoDB副本集设置

在本教程中我们使用同一个MongoDB来做MongoDB主从的实验, 操作步骤如下:

1、关闭正在运行的MongoDB服务器。

现在我们通过指定 --replSet 选项来启动mongoDB。--replSet 基本语法格式如下:

mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"

实例

mongod --port 27017 --dbpath "D:set upmongodbdata" --replSet rs0

以上实例会启动一个名为rs0的MongoDB实例,其端口号为27017。

启动后打开命令提示框并连接上mongoDB服务。

在Mongo客户端使用命令rs.initiate()来启动一个新的副本集。

我们可以使用rs.conf()来查看副本集的配置

查看副本集姿态使用 rs.status() 命令


副本集添加成员

添加副本集的成员,我们需要使用多条服务器来启动mongo服务。进入Mongo客户端,并使用rs.add()方法来添加副本集的成员。

语法

rs.add() 命令基本语法格式如下:
>rs.add(HOST_NAME:PORT)

实例

假设你已经启动了一个名为mongod1.net,端口号为27017的Mongo服务。 在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:

>rs.add("mongod1.net:27017")>

MongoDB中你只能通过主节点将Mongo服务添加到副本集中, 判断当前运行的Mongo服务是否为主节点可以使用命令db.isMaster() 。

MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。

MongoDB 分片


分片

在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。

当MongoDB存储海量的数据时,一台机器可能不足以存储数据也足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。


为什么使用分片

  • 复制所有的写入操作到主节点
  • 延迟的敏感数据会在主节点查询
  • 单个副本集限制在12个节点
  • 当请求量巨大时会出现内存不足。
  • 本地磁盘不足
  • 垂直扩展价格昂贵

MongoDB分片

下图展示了在MongoDB中使用分片集群结构分布:

上图中主要有如下所述三个主要组件:

  • Shard:

    用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个relica set承担,防止主机单点故障

  • Config Server:

    mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。

  • Query Routers:

    前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。


分片实例

分片结构端口分布如下:

Shard Server 1:27020Shard Server 2:27021Shard Server 3:27022Shard Server 4:27023Config Server :27100Route Process:40000

步骤一:启动Shard Server

[root@100 /]# mkdir -p /www/mongoDB/shard/s0[root@100 /]# mkdir -p /www/mongoDB/shard/s1[root@100 /]# mkdir -p /www/mongoDB/shard/s2[root@100 /]# mkdir -p /www/mongoDB/shard/s3[root@100 /]# mkdir -p /www/mongoDB/shard/log[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork....[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27023 --dbpath=/www/mongoDB/shard/s3 --logpath=/www/mongoDB/shard/log/s3.log --logappend --fork

步骤二: 启动Config Server

[root@100 /]# mkdir -p /www/mongoDB/shard/config[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend --fork

注意:这里我们完全可以像启动普通mongodb服务一样启动,不需要添加—shardsvr和configsvr参数。因为这两个参数的作用就是改变启动端口的,所以我们自行指定了端口就可以。

步骤三: 启动Route Process

/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500

mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB.

步骤四: 配置Sharding

接下来,我们使用MongoDB Shell登录到mongos,添加Shard节点

[root@100 shard]# /usr/local/mongoDB/bin/mongo admin --port 40000MongoDB shell version: 2.0.7connecting to: 127.0.0.1:40000/adminmongos> db.runCommand({ addshard:"localhost:27020" }){ "shardAdded" : "shard0000", "ok" : 1 }......mongos> db.runCommand({ addshard:"localhost:27029" }){ "shardAdded" : "shard0009", "ok" : 1 }mongos> db.runCommand({ enablesharding:"test" }) #设置分片存储的数据库{ "ok" : 1 }mongos> db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}}){ "collectionsharded" : "test.log", "ok" : 1 }

步骤五: 程序代码内无需太大更改,直接按照连接普通的mongo数据库那样,将数据库连接接入接口40000

MongoDB 备份(mongodump)与恢复(mongorerstore)


MongoDB数据备份

在Mongodb中我们使用mongodump命令来备份MongoDB数据。该命令可以导出所有数据到指定目录中。

mongodump命令可以通过参数指定导出的数据量级转存的服务器。

语法

mongodump命令脚本语法如下:

>mongodump -h dbhost -d dbname -o dbdirectory
  • -h:

    MongDB所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017

  • -d:

    需要备份的数据库实例,例如:test

  • -o:

    备份的数据存放位置,例如:c:datadump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。

实例

在本地使用 27017 启动你的mongod服务。打开命令提示符窗口,进入MongoDB安装目录的bin目录输入命令mongodump:

>mongodump

执行以上命令后,客户端会连接到ip为 127.0.0.1 端口号为 27017 的MongoDB服务上,并备份所有数据到 bin/dump/ 目录中。命令输出结果如下:

MongoDB数据备份

mongodump 命令可选参数列表如下所示:

语法描述实例
mongodump --host HOST_NAME --port PORT_NUMBER该命令将备份所有MongoDB数据mongodump --host 51coolma.cn --port 27017
mongodump --dbpath DB_PATH --out BACKUP_DIRECTORY mongodump --dbpath /data/db/ --out /data/backup/
mongodump --collection COLLECTION --db DB_NAME该命令将备份指定数据库的集合。mongodump --collection mycol --db test

MongoDB数据恢复

mongodb使用 mongorerstore 命令来恢复备份的数据。

语法

mongorestore命令脚本语法如下:

>mongorestore -h dbhost -d dbname --directoryperdb dbdirectory
  • -h:

    MongoDB所在服务器地址

  • -d:

    需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2

  • --directoryperdb:

    备份数据所在位置,例如:c:datadump est,这里为什么要多加一个test,而不是备份时候的dump,读者自己查看提示吧!

  • --drop:

    恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦!

接下来我们执行以下命令:

>mongorestore

执行以上命令输出结果如下:

MongoDB数据恢复

MongoDB 监控

在你已经安装部署并允许MongoDB服务后,你必须要了解MongoDB的运行情况,并查看MongoDB的性能。这样在大流量得情况下可以很好的应对并保证MongoDB正常运作。

MongoDB中提供了mongostat 和 mongotop 两个命令来监控MongoDB的运行情况。


mongostat 命令

mongostat是mongodb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。

启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongostat命令,如下所示:

D:set upmongodbin>mongostat

以上命令输出结果如下:

mongotop 命令

mongotop也是mongodb下的一个内置工具,mongotop提供了一个方法,用来跟踪一个MongoDB的实例,查看哪些大量的时间花费在读取和写入数据。 mongotop提供每个集合的水平的统计数据。默认情况下,mongotop返回值的每一秒。

启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongotop命令,如下所示:

D:set upmongodbin>mongotop

以上命令执行输出结果如下:

带参数实例

 E:mongodb-win32-x86_64-2.2.1in>mongotop 10

后面的10是<sleeptime>参数 ,可以不使用,等待的时间长度,以秒为单位,mongotop等待调用之间。通过的默认mongotop返回数据的每一秒。

 E:mongodb-win32-x86_64-2.2.1in>mongotop --locks

报告每个数据库的锁的使用中,使用mongotop - 锁,这将产生以下输出:

输出结果字段说明:

  • ns:

    包含数据库命名空间,后者结合了数据库名称和集合。

  • db:

    包含数据库的名称。名为 . 的数据库针对全局锁定,而非特定数据库。

  • total:

    mongod花费的时间工作在这个命名空间提供总额。

  • read:

    提供了大量的时间,这mongod花费在执行读操作,在此命名空间。

  • write:

    提供这个命名空间进行写操作,这mongod花了大量的时间。

MongoDB Java

环境配置

在Java程序中如果要使用MongoDB,你需要确保已经安装了Java环境及MongoDB JDBC 驱动。

你可以参考本站的Java教程来安装Java程序。现在让我们来检测你是否安装了 MongoDB JDBC 驱动。

  • 首先你必须下载mongo jar包,下载地址:https://github.com/mongodb/mongo-java-driver/downloads, 请确保下载最新版本。
  • 你需要将mongo.jar包含在你的 classpath 中。。

连接数据库

连接数据库,你需要指定数据库名称,如果指定的数据库不存在,mongo会自动创建数据库。

连接数据库的Java代码如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   		 // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );		 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);		 System.out.println("Authentication: "+auth);      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

现在,让我们来编译运行程序并创建数据库test。

你可以更加你的实际环境改变MongoDB JDBC驱动的路径。

本实例将MongoDB JDBC启动包 mongo-2.10.1.jar 放在本地目录下:

$javac MongoDBJDBC.java$java -classpath ".:mongo-2.10.1.jar" MongoDBJDBCConnect to database successfullyAuthentication: true

如果你使用的是Window系统,你可以按以下命令来编译执行程序:

$javac MongoDBJDBC.java$java -classpath ".;mongo-2.10.1.jar" MongoDBJDBCConnect to database successfullyAuthentication: true

如果用户名及密码正确,则Authentication 的值为true。


创建集合

我们可以使用com.mongodb.DB类中的createCollection()来创建集合

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	     // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);         DBCollection coll = db.createCollection("mycol");         System.out.println("Collection created successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection created successfully

获取集合

我们可以使用com.mongodb.DBCollection类的 getCollection() 方法来获取一个集合

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	     // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);         DBCollection coll = db.createCollection("mycol");         System.out.println("Collection created successfully");         DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection created successfullyCollection mycol selected successfully

插入文档

我们可以使用com.mongodb.DBCollection类的 insert() 方法来插入一个文档

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   		 // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         BasicDBObject doc = new BasicDBObject("title", "MongoDB").            append("description", "database").            append("likes", 100).            append("url", "//www.51coolma.cn/mongodb/").            append("by", "51coolma.cn");         coll.insert(doc);         System.out.println("Document inserted successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyDocument inserted successfully

检索所有文档

我们可以使用com.mongodb.DBCollection类中的 find() 方法来获取集合中的所有文档。

此方法返回一个游标,所以你需要遍历这个游标。

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   		// 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );          // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         DBCursor cursor = coll.find();         int i=1;         while (cursor.hasNext()) {             System.out.println("Inserted Document: "+i);             System.out.println(cursor.next());             i++;         }      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyInserted Document: 1{   "_id" : ObjectId(7df78ad8902c),   "title": "MongoDB",   "description": "database",   "likes": 100,   "url": "//www.51coolma.cn/mongodb/",   "by": "51coolma.cn"}

更新文档

你可以使用 com.mongodb.DBCollection 类中的 update() 方法来更新集合中的文档。

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	 // 连接到Mongodb服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到你的数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         DBCursor cursor = coll.find();         while (cursor.hasNext()) {             DBObject updateDocument = cursor.next();            updateDocument.put("likes","200")            coll.update(updateDocument);          }         System.out.println("Document updated successfully");         cursor = coll.find();         int i=1;         while (cursor.hasNext()) {             System.out.println("Updated Document: "+i);             System.out.println(cursor.next());             i++;         }      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyDocument updated successfullyUpdated Document: 1{   "_id" : ObjectId(7df78ad8902c),   "title": "MongoDB",   "description": "database",   "likes": 200,   "url": "//www.51coolma.cn/mongodb/",   "by": "51coolma.cn"}

删除第一个文档

要删除集合中的第一个文档,首先你需要使用com.mongodb.DBCollection类中的 findOne()方法来获取第一个文档,然后使用remove 方法删除。

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	 // 连接到Mongodb服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到你的数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         DBObject myDoc = coll.findOne();         coll.remove(myDoc);         DBCursor cursor = coll.find();         int i=1;         while (cursor.hasNext()) {             System.out.println("Inserted Document: "+i);             System.out.println(cursor.next());             i++;         }         System.out.println("Document deleted successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyDocument deleted successfully

你还可以使用 save(), limit(), skip(), sort() 等方法来操作MongoDB数据库。

jQuery parent descendant 选择器

jQuery 选择器 jQuery 选择器

实例

选取 <div> 元素的后代的所有 <span> 元素:

$("div span")

尝试一下 »

定义和用法

("parent descendant") 选择器选取指定元素的后代的所有元素。

元素的后代可以是元素的第一代、第二代、第三代等等。


语法

("parent descendant")

参数描述
parent必需。规定要选取的父元素。
descendant必需。规定要选取的(指定父元素的)后代元素。


实例

尝试一下 - 实例

选取 <ul> 元素的后代的所有 <li> 元素
如何选取 <ul> 元素的后代的所有 <li> 元素。


jQuery 选择器 jQuery 选择器

MongoDB PHP

在php中使用mongodb你必须使用 mongodb的php驱动。

MongoDB PHP在各平台上的安装及驱动包下载请查看:PHP安装MongoDB扩展驱动

确保连接及选择一个数据库

为了确保正确连接,你需要指定数据库名,如果数据库在mongoDB中不存在,mongoDB会自动创建

代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selected

创建集合

创建集合的代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->createCollection("mycol");   echo "Collection created succsessfully";?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection created succsessfully

插入文档

在mongoDB中使用 insert() 方法插入文档:

插入文档代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";   $document = array(       "title" => "MongoDB",       "description" => "database",       "likes" => 100,      "url" => "//www.51coolma.cn/mongodb/",      "by", "51coolma.cn"   );   $collection->insert($document);   echo "Document inserted successfully";?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfullyDocument inserted successfully

查找文档

使用find() 方法来读取集合中的文档。

读取使用文档的代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";   $cursor = $collection->find();   // 迭代显示文档标题   foreach ($cursor as $document) {      echo $document["title"] . "
";   }?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfully{   "title": "MongoDB"}

更新文档

使用 update() 方法来更新文档。

以下实例将更新文档中的标题为' MongoDB Tutorial', 代码片段如下:

<pre><?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";   // 更新文档   $collection->update(array("title"=>"MongoDB"), array('$set'=>array("title"=>"MongoDB Tutorial")));   echo "Document updated successfully";   // 显示更新后的文档   $cursor = $collection->find();   // 循环显示文档标题   echo "Updated document";   foreach ($cursor as $document) {      echo $document["title"] . "
";   }?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfullyDocument updated successfullyUpdated document{   "title": "MongoDB Tutorial"}

删除文档

使用 remove() 方法来删除文档。

以下实例中我们将移除 'title' 为 'MongoDB Tutorial' 的数据记录。, 代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";      // 移除文档   $collection->remove(array("title"=>"MongoDB Tutorial"),false);   echo "Documents deleted successfully";      // 显示可用文档数据   $cursor = $collection->find();   // iterate cursor to display title of documents   echo "Updated document";   foreach ($cursor as $document) {      echo $document["title"] . "
";   }?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfullyDocuments deleted successfully

除了以上实例外,在php中你还可以使用findOne(), save(), limit(), skip(), sort()等方法来操作Mongodb数据库。

PHP7 MongDB 安装与使用

本文教程只适合在 PHP7 的环境,如果你是 PHP5 环境,你可以参阅 PHP MongDB 安装与使用

PHP7 Mongdb 扩展安装

我们使用 pecl 命令来安装:

$ /usr/local/php7/bin/pecl install mongodb

执行成功后,会输出以下结果:

……Build process completed successfullyInstalling '/usr/local/php7/lib/php/extensions/no-debug-non-zts-20151012/mongodb.so'install ok: channel://pecl.php.net/mongodb-1.1.7configuration option "php_ini" is not set to php.ini locationYou should add "extension=mongodb.so" to php.ini

接下来我们打开 php.ini 文件,添加 extension=mongodb.so 配置。

可以直接执行以下命令来添加。

$ echo "extension=mongodb.so" >> `/usr/local/php7/bin/php --ini | grep "Loaded Configuration" | sed -e "s|.*:s*||"`

注意:以上执行的命令中 php7 的安装目录为 /usr/local/php7/,如果你安装在其他目录,需要相应修改 pecl 与 php 命令的路径。


Mongodb 使用

PHP7 连接 MongoDB 语法如下:

$manager = new MongoDBDriverManager("mongodb://localhost:27017");

插入数据

将 name 为"W3Cschool教程" 的数据插入到 test 数据库的 51coolma 集合中。

<?php$bulk = new MongoDBDriverBulkWrite;$document = ['_id' => new MongoDBBSONObjectID, 'name' => 'W3Cschool教程'];$_id= $bulk->insert($document);var_dump($_id);$manager = new MongoDBDriverManager("mongodb://localhost:27017");  $writeConcern = new MongoDBDriverWriteConcern(MongoDBDriverWriteConcern::MAJORITY, 1000);$result = $manager->executeBulkWrite('test.51coolma', $bulk, $writeConcern);?>

读取数据

这里我们将三个网址数据插入到 test 数据库的 sites 集合,并读取迭代出来:

<?php$manager = new MongoDBDriverManager("mongodb://localhost:27017");  // 插入数据$bulk = new MongoDBDriverBulkWrite;$bulk->insert(['x' => 1, 'name'=>'W3Cschool教程', 'url' => 'http://www.51coolma.cn']);$bulk->insert(['x' => 2, 'name'=>'Google', 'url' => 'http://www.google.com']);$bulk->insert(['x' => 3, 'name'=>'taobao', 'url' => 'http://www.taobao.com']);$manager->executeBulkWrite('test.sites', $bulk);$filter = ['x' => ['$gt' => 1]];$options = [    'projection' => ['_id' => 0],    'sort' => ['x' => -1],];// 查询数据$query = new MongoDBDriverQuery($filter, $options);$cursor = $manager->executeQuery('test.sites', $query);foreach ($cursor as $document) {    print_r($document);}?>

输出结果为:

stdClass Object(    [x] => 3    [name] => taobao    [url] => http://www.taobao.com)stdClass Object(    [x] => 2    [name] => Google    [url] => http://www.google.com)

更新数据

接下来我们将更新 test 数据库 sites 集合中 x 为 2 的数据:

<?php$bulk = new MongoDBDriverBulkWrite;$bulk->update(    ['x' => 2],    ['$set' => ['name' => '51coolma在线工具', 'url' => '123.51coolma.cn/webtools']],    ['multi' => false, 'upsert' => false]);$manager = new MongoDBDriverManager("mongodb://localhost:27017");  $writeConcern = new MongoDBDriverWriteConcern(MongoDBDriverWriteConcern::MAJORITY, 1000);$result = $manager->executeBulkWrite('test.sites', $bulk, $writeConcern);?>

接下来我们使用 "db.sites.find()" 命令查看数据的变化,x 为 2 的数据已经变成了51coolma在线工具:


删除数据

以下实例删除了 x 为 1 和 x 为 2的数据,注意 limit 参数的区别:

<?php$bulk = new MongoDBDriverBulkWrite;$bulk->delete(['x' => 1], ['limit' => 1]);   // limit 为 1 时,删除第一条匹配数据$bulk->delete(['x' => 2], ['limit' => 0]);   // limit 为 0 时,删除所有匹配数据$manager = new MongoDBDriverManager("mongodb://localhost:27017");  $writeConcern = new MongoDBDriverWriteConcern(MongoDBDriverWriteConcern::MAJORITY, 1000);$result = $manager->executeBulkWrite('test.sites', $bulk, $writeConcern);?>

更多使用方法请参考:http://php.net/manual/en/book.mongodb.php


MongoDB 关系

MongoDB 的关系表示多个文档之间在逻辑上的相互联系。

文档间可以通过嵌入和引用来建立联系。

MongoDB 中的关系可以是:

  • 1:1 (1对1)
  • 1: N (1对多)
  • N: 1 (多对1)
  • N: N (多对多)

接下来我们来考虑下用户与用户地址的关系。

一个用户可以有多个地址,所以是一对多的关系。

以下是 user 文档的简单结构:

{   "_id":ObjectId("52ffc33cd85242f436000001"),   "name": "Tom Hanks",   "contact": "987654321",   "dob": "01-01-1991"}

以下是 address 文档的简单结构:

{   "_id":ObjectId("52ffc4a5d85242602e000000"),   "building": "22 A, Indiana Apt",   "pincode": 123456,   "city": "Los Angeles",   "state": "California"} 

嵌入式关系

使用嵌入式方法,我们可以把用户地址嵌入到用户的文档中:

   "_id":ObjectId("52ffc33cd85242f436000001"),   "contact": "987654321",   "dob": "01-01-1991",   "name": "Tom Benzamin",   "address": [      {         "building": "22 A, Indiana Apt",         "pincode": 123456,         "city": "Los Angeles",         "state": "California"      },      {         "building": "170 A, Acropolis Apt",         "pincode": 456789,         "city": "Chicago",         "state": "Illinois"      }]} 

以上数据保存在单一的文档中,可以比较容易的获取很维护数据。 你可以这样查询用户的地址:

>db.users.findOne({"name":"Tom Benzamin"},{"address":1})

注意:以上查询中 dbusers 表示数据库和集合。

这种数据结构的缺点是,如果用户和用户地址在不断增加,数据量不断变大,会影响读写性能。

引用式关系

引用式关系是设计数据库时经常用到的方法,这种方法把用户数据文档和用户地址数据文档分开,通过引用文档的 id 字段来建立关系。

{   "_id":ObjectId("52ffc33cd85242f436000001"),   "contact": "987654321",   "dob": "01-01-1991",   "name": "Tom Benzamin",   "address_ids": [      ObjectId("52ffc4a5d85242602e000000"),      ObjectId("52ffc4a5d85242602e000001")   ]}

以上实例中,用户文档的 address_ids 字段包含用户地址的对象id(ObjectId)数组。

我们可以读取这些用户地址的对象id(ObjectId)来获取用户的详细地址信息。

这种方法需要两次查询,第一次查询用户地址的对象id(ObjectId),第二次通过查询的id获取用户的详细地址信息。

>var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})

MongoDB 数据库引用

在上一章节MongoDB关系中我们提到了MongoDB的引用来规范数据结构文档。

MongoDB 引用有两种:

  • 手动引用(Manual References)
  • DBRefs

DBRefs vs 手动引用

考虑这样的一个场景,我们在不同的集合中 (address_home, address_office, address_mailing, 等)存储不同的地址(住址,办公室地址,邮件地址等)。

这样,我们在调用不同地址时,也需要指定集合,一个文档从多个集合引用文档,我们应该使用 DBRefs。


使用 DBRefs

DBRef的形式:

{ $ref : , $id : , $db :  }

三个字段表示的意义为:

  • $ref:集合名称
  • $id:引用的id
  • $db:数据库名称,可选参数

以下实例中用户数据文档使用了 DBRef, 字段 address:

{   "_id":ObjectId("53402597d852426020000002"),   "address": {   "$ref": "address_home",   "$id": ObjectId("534009e4d852427820000002"),   "$db": "51coolmacc"},   "contact": "987654321",   "dob": "01-01-1991",   "name": "Tom Benzamin"}

address DBRef 字段指定了引用的地址文档是在 address_home 集合下的 51coolmacc 数据库,id 为 534009e4d852427820000002。

以下代码中,我们通过指定 $ref 参数(address_home 集合)来查找集合中指定id的用户地址信息:

>var user = db.users.findOne({"name":"Tom Benzamin"})>var dbRef = user.address>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})

以上实例返回了 address_home 集合中的地址数据:

{   "_id" : ObjectId("534009e4d852427820000002"),   "building" : "22 A, Indiana Apt",   "pincode" : 123456,   "city" : "Los Angeles",   "state" : "California"}

MongoDB 覆盖索引查询

官方的 MongoDB 的文档中说明,覆盖查询是以下的查询:

  • 所有的查询字段是索引的一部分
  • 所有的查询返回字段在同一个索引中

由于所有出现在查询中的字段是索引的一部分, MongoDB 无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询结果。

因为索引存在于RAM中,从索引中获取数据比通过扫描文档读取数据要快得多。


为了测试盖索引查询,使用以下 mycol 集合:

{ "_id" : 1, "name" : "tom", "sex" : "男", "score" : 100, "age" : 34 }{ "_id" : 2, "name" : "jeke", "sex" : "男", "score" : 90, "age" : 24 }{ "_id" : 3, "name" : "kite", "sex" : "女", "score" : 40, "age" : 36 }{ "_id" : 4, "name" : "herry", "sex" : "男", "score" : 90, "age" : 56 }{ "_id" : 5, "name" : "marry", "sex" : "女", "score" : 70, "age" : 18 }{ "_id" : 6, "name" : "john", "sex" : "男", "score" : 100, "age" : 31 }

我们在 mycol 集合中创建联合索引,字段为 sex 和 name :

db.mycol.ensureIndex({sex : 1, name : 1})

现在,该索引会覆盖以下查询:

db.mycol.find({sex: '男'},{name : 1, _id : 0})

 

也就是说,对于上述查询,MongoDB 的不会去数据库文件中查找。相反,它会从索引中提取数据,这是非常快速的数据查询。

由于我们的索引中不包括 _id 字段,_id 在查询中会默认返回,我们可以在 MongoDB 的查询结果集中排除它。

下面的实例没有排除 _id,查询就不会被覆盖:

db.mycol.find({sex: '男'},{name : 1})

 

最后,如果所有索引字段是一个数组,不能使用覆盖索引查询。


MongoDB 查询分析

MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。

MongoDB 查询分析常用函数有:explain() 和 hint()。


使用 explain()

explain 操作提供了查询信息,使用索引及查询统计等。有利于我们对索引的优化。

接下来我们在 users 集合中创建 gender 和 user_name 的索引:

>db.users.ensureIndex({gender:1,user_name:1})</p><p>现在在查询语句中使用 explain :</p><pre>>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()

以上的 explain() 查询返回如下结果:

{   "cursor" : "BtreeCursor gender_1_user_name_1",   "isMultiKey" : false,   "n" : 1,   "nscannedObjects" : 0,   "nscanned" : 1,   "nscannedObjectsAllPlans" : 0,   "nscannedAllPlans" : 1,   "scanAndOrder" : false,   "indexOnly" : true,   "nYields" : 0,   "nChunkSkips" : 0,   "millis" : 0,   "indexBounds" : {      "gender" : [         [            "M",            "M"         ]      ],      "user_name" : [         [            {               "$minElement" : 1            },            {               "$maxElement" : 1            }         ]      ]   }}

现在,我们看看这个结果集的字段:

  • indexOnly: 字段为 true ,表示我们使用了索引。
  • cursor:因为这个查询使用了索引,MongoDB中索引存储在B树结构中,所以这是也使用了BtreeCursor类型的游标。如果没有使用索引,游标的类型是BasicCursor。这个键还会给出你所使用的索引的名称,你通过这个名称可以查看当前数据库下的system.indexes集合(系统自动创建,由于存储索引信息,这个稍微会提到)来得到索引的详细信息。
  • n:当前查询返回的文档数量。
  • nscanned/nscannedObjects:表明当前这次查询一共扫描了集合中多少个文档,我们的目的是,让这个数值和返回文档的数量越接近越好。
  • millis:当前查询所需时间,毫秒数。
  • indexBounds:当前查询具体使用的索引。

使用 hint()

虽然MongoDB查询优化器一般工作的很不错,但是也可以使用hints来强迫MongoDB使用一个指定的索引。

这种方法某些情形下会提升性能。 一个有索引的collection并且执行一个多字段的查询(一些字段已经索引了)。

如下查询实例指定了使用 gender 和 user_name 索引字段来查询:

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})

可以使用 explain() 函数来分析以上查询:

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()

MongoDB 原子操作

mongodb不支持事务,所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。

但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。

所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况。


原子操作数据模型

考虑下面的例子,图书馆的书籍及结账信息。

实例说明了在一个相同的文档中如何确保嵌入字段关联原子操作(update:更新)的字段是同步的。

book = {          _id: 123456789,          title: "MongoDB: The Definitive Guide",          author: [ "Kristina Chodorow", "Mike Dirolf" ],          published_date: ISODate("2010-09-24"),          pages: 216,          language: "English",          publisher_id: "oreilly",          available: 3,          checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]        }

你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。

在同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:

db.books.findAndModify ( {   query: {            _id: 123456789,            available: { $gt: 0 }          },   update: {             $inc: { available: -1 },             $push: { checkout: { by: "abc", date: new Date() } }           }} )

原子操作常用命令

$set

用来指定一个键并更新键值,若键不存在并创建。

{ $set : { field : value } }

$unset

用来删除一个键。

{ $unset : { field : 1} }

$inc

$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。

{ $inc : { field : value } }

$push

用法:

{ $push : { field : value } }

把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。

$pushAll

同$push,只是一次可以追加多个值到一个数组字段内。

{ $pushAll : { field : value_array } }

$pull

从数组field内删除一个等于value值。

{ $pull : { field : _value } }

$addToSet

增加一个值到数组内,而且只有当这个值不在数组内才增加。

$pop

删除数组的第一个或最后一个元素

{ $pop : { field : 1 } }

$rename

修改字段名称

{ $rename : { old_field_name : new_field_name } }

$bit

位操作,integer类型

{$bit : { field : {and : 5}}}

偏移操作符

> t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] } > t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true ) > t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }

MongoDB 高级索引

考虑以下文档集合(users ):

{   "address": {      "city": "Los Angeles",      "state": "California",      "pincode": "123"   },   "tags": [      "music",      "cricket",      "blogs"   ],   "name": "Tom Benzamin"}

以上文档包含了 address 子文档和 tags 数组。


索引数组字段

假设我们基于标签来检索用户,为此我们需要对集合中的数组 tags 建立索引。

在数组中创建索引,需要对数组中的每个字段依次建立索引。所以在我们为数组 tags 创建索引时,会为 music、cricket、blogs三个值建立单独的索引。

使用以下命令创建数组索引:

>db.users.ensureIndex({"tags":1})

创建索引后,我们可以这样检索集合的 tags 字段:

>db.users.find({tags:"cricket"})

为了验证我们使用使用了索引,可以使用 explain 命令:

>db.users.find({tags:"cricket"}).explain()

以上命令执行结果中会显示 "cursor" : "BtreeCursor tags_1" ,则表示已经使用了索引。


索引子文档字段

假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。

为子文档的三个字段创建索引,命令如下:

>db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})

一旦创建索引,我们可以使用子文档的字段来检索数据:

>db.users.find({"address.city":"Los Angeles"})   

记住查询表达式必须遵循指定的索引的顺序。所以上面创建的索引将支持以下查询:

>db.users.find({"address.city":"Los Angeles","address.state":"California"}) 

同样支持以下查询:

>db.users.find({"address.city":"LosAngeles","address.state":"California","address.pincode":"123"})

MongoDB 索引限制


额外开销

每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果你很少对集合进行读取操作,建议不使用索引。


内存(RAM)使用

由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。

如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。


查询限制

索引不能被以下的查询使用:

  • 正则表达式及非操作符,如 $nin, $not, 等。
  • 算术运算符,如 $mod, 等。
  • $where 子句

所以,检测你的语句是否使用索引是一个好的习惯,可以用explain来查看。


索引键限制

从2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。


插入文档超过索引键限制

如果文档的索引字段值超过了索引键的限制,MongoDB不会将任何文档转换成索引的集合。与mongorestore和mongoimport工具类似。


最大范围

  • 集合中索引不能超过64个
  • 索引名的长度不能超过125个字符
  • 一个复合索引最多可以有31个字段

MongoDB ObjectId


在前面几个章节中我们已经使用了MongoDB 的对象 Id(ObjectId)。

在本章节中,我们将了解的ObjectId的结构。

ObjectId 是一个12字节 BSON 类型数据,有以下格式:

  • 前4个字节表示时间戳
  • 接下来的3个字节是机器标识码
  • 紧接的两个字节由进程id组成(PID)
  • 最后三个字节是随机数。

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。

在一个集合里面,每个集合都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。

MongoDB采用ObjectId,而不是其他比较常规的做法(比如自动增加的主键)的主要原因,因为在多个 服务器上同步自动增加主键值既费力还费时。


创建新的ObjectId

使用以下代码生成新的ObjectId:

>newObjectId = ObjectId()

上面的语句返回以下唯一生成的id:

ObjectId("5349b4ddd2781d08c09890f3")

你也可以使用生成的id来取代MongoDB自动生成的ObjectId:

>myObjectId = ObjectId("5349b4ddd2781d08c09890f4")

创建文档的时间戳

由于 ObjectId 中存储了 4 个字节的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:

>ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()

以上代码将返回 ISO 格式的文档创建时间:

ISODate("2014-04-12T21:49:17Z")

ObjectId 转换为字符串

在某些情况下,您可能需要将ObjectId转换为字符串格式。你可以使用下面的代码:

>new ObjectId.str

以上代码将返回Guid格式的字符串::

5349b4ddd2781d08c09890f3

MongoDB Map Reduce

Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。

MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。


MapReduce 命令

以下是MapReduce的基本语法:

>db.collection.mapReduce(   function() {emit(key,value);},  //map 函数   function(key,values) {return reduceFunction},   //reduce 函数   {      out: collection,      query: document,      sort: document,      limit: number   })

使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将key 与 value 传递给 Reduce 函数进行处理。

Map 函数必须调用 emit(key, value) 返回键值对。

参数说明:

  • map :映射函数 (生成键值对序列,作为 reduce 函数参数)。
  • reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。
  • out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
  • query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
  • sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
  • limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)

使用 MapReduce

考虑以下文档结构存储用户的文章,文档存储了用户的 user_name 和文章的 status字段:

{   "post_text": "51coolma.cn W3Cschool教程,最全的技术文档。",   "user_name": "mark",   "status":"active"}

现在,我们将在 posts 集合中使用 mapReduce 函数来选取已发布的文章,并通过user_name分组,计算每个用户的文章数:

>db.posts.mapReduce(    function() { emit(this.user_id,1); },    function(key, values) {return Array.sum(values)},       {           query:{status:"active"},           out:"post_total"       })

以上 mapReduce 输出结果为:

{   "result" : "post_total",   "timeMillis" : 9,   "counts" : {      "input" : 4,      "emit" : 4,      "reduce" : 2,      "output" : 2   },   "ok" : 1,}

结果表明,共有4个符合查询条件(status:"active")的文档, 在map函数中生成了4个键值对文档,最后使用reduce函数将相同的键值分为两组。

具体参数说明:

  • result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。
  • timeMillis:执行花费的时间,毫秒为单位
  • input:满足条件被发送到map函数的文档个数
  • emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
  • ouput:结果集合中的文档个数(count对调试非常有帮助)
  • ok:是否成功,成功为1
  • err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大

使用 find 操作符来查看 mapReduce 的查询结果:

>db.posts.mapReduce(    function() { emit(this.user_id,1); },    function(key, values) {return Array.sum(values)},       {           query:{status:"active"},           out:"post_total"       }).find()

以上查询显示如下结果,两个用户 tom 和 mark 有两个发布的文章:

{ "_id" : "tom", "value" : 2 }{ "_id" : "mark", "value" : 2 }

用类似的方式,MapReduce可以被用来构建大型复杂的聚合查询。

Map函数和Reduce函数可以使用 JavaScript 来实现,是的MapReduce的使用非常灵活和强大。

MongoDB 全文检索

全文检索对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。

这个过程类似于通过字典中的检索字表查字的过程。

MongoDB 从 2.4 版本开始支持全文检索,目前支持15种语言(暂时不支持中文)的全文索引。

  • danish
  • dutch
  • english
  • finnish
  • french
  • german
  • hungarian
  • italian
  • norwegian
  • portuguese
  • romanian
  • russian
  • spanish
  • swedish
  • turkish

启用全文检索

MongoDB 在 2.6 版本以后是默认开启全文检索的,如果你使用之前的版本,你需要使用以下代码来启用全文检索:

>db.adminCommand({setParameter:true,textSearchEnabled:true})

或者使用命令:

mongod --setParameter textSearchEnabled=true

创建全文索引

考虑以下 posts 集合的文档数据,包含了文章内容(post_text)及标签(tags):

{   "post_text": "enjoy the mongodb articles on 51coolma.cn",   "tags": [      "mongodb",      "51coolma"   ]}

我们可以对 post_text 字段建立全文索引,这样我们可以搜索文章内的内容:

>db.posts.ensureIndex({post_text:"text"})

使用全文索引

现在我们已经对 post_text 建立了全文索引,我们可以搜索文章中的关键词51coolma.cn:

>db.posts.find({$text:{$search:"51coolma.cn"}})

以下命令返回了如下包含51coolma.cn关键词的文档数据:

{    "_id" : ObjectId("53493d14d852429c10000002"),    "post_text" : "enjoy the mongodb articles on 51coolma.cn",    "tags" : [ "mongodb", "51coolma" ]}{   "_id" : ObjectId("53493d1fd852429c10000003"),    "post_text" : "writing tutorials on 51coolma.cn",   "tags" : [ "mongodb", "tutorial" ] }

如果你使用的是旧版本的MongoDB,你可以使用以下命令:

>db.posts.runCommand("text",{search:" 51coolma.cn"})

使用全文索引可以提高搜索效率。


删除全文索引

删除已存在的全文索引,可以使用 find 命令查找索引名:

>db.posts.getIndexes()

通过以上命令获取索引名,本例的索引名为post_text_text,执行以下命令来删除索引:

>db.posts.dropIndex("post_text_text")

MongoDB 正则表达式

正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。

许多程序设计语言都支持利用正则表达式进行字符串操作。

MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。

MongoDB使用PCRE (Perl Compatible Regular Expression) 作为正则表达式语言。

不同于全文检索,我们使用正则表达式不需要做任何配置。

考虑以下 posts 集合的文档结构,该文档包含了文章内容和标签:

{   "post_text": "enjoy the mongodb articles on tutorialspoint",   "tags": [      "mongodb",      "tutorialspoint"   ]}

使用正则表达式

以下命令使用正则表达式查找包含 51coolma.cn 字符串的文章:

>db.posts.find({post_text:{$regex:"51coolma.cn"}})

以上查询也可以写为:

>db.posts.find({post_text:/51coolma.cn/})

不区分大小写的正则表达式

如果检索需要不区分大小写,我们可以设置 $options 为 $i。

以下命令将查找不区分大小写的字符串 51coolma.cn:

>db.posts.find({post_text:{$regex:"51coolma.cn",$options:"$i"}})

集合中会返回所有包含字符串 51coolma.cn 的数据,且不区分大小写:

{   "_id" : ObjectId("53493d37d852429c10000004"),   "post_text" : "hey! this is my post on  W3Cschool.cc",    "tags" : [ "tutorialspoint" ]} 

数组元素使用正则表达式

我们还可以在数组字段中使用正则表达式来查找内容。 这在标签的实现上非常有用,如果你需要查找包含以 tutorial 开头的标签数据(tutorial 或 tutorials 或 tutorialpoint 或 tutorialphp), 你可以使用以下代码:

>db.posts.find({tags:{$regex:"tutorial"}})

优化正则表达式查询

  • 如果你的文档中字段设置了索引,那么使用索引相比于正则表达式匹配查找所有的数据查询速度更快。
  • 如果正则表达式是前缀表达式,所有匹配的数据将以指定的前缀字符串为开始。例如: 如果正则表达式为 ^tut ,查询语句将查找以 tut 为开头的字符串。

MongoDB GridFS

GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。

GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。

GridFS 可以更好的存储大于16M的文件。

GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。

GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。

每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。

以下是简单的 fs.files 集合文档:

{   "filename": "test.txt",   "chunkSize": NumberInt(261120),   "uploadDate": ISODate("2014-04-13T11:32:33.557Z"),   "md5": "7b762939321e146569b07f72c62cca4f",   "length": NumberInt(646)}

以下是简单的 fs.chunks 集合文档:

{   "files_id": ObjectId("534a75d19f54bfec8a2fe44b"),   "n": NumberInt(0),   "data": "Mongo Binary Data"}

GridFS 添加文件

现在我们使用 GridFS 的 put 命令来存储 mp3 文件。 调用 MongoDB 安装目录下bin的 mongofiles.exe工具。

打开命令提示符,进入到MongoDB的安装目录的bin目录中,找到mongofiles.exe,并输入下面的代码:

>mongofiles.exe -d gridfs put song.mp3

GridFS 是存储文件的数据名称。如果不存在该数据库,MongoDB会自动创建。Song.mp3 是音频文件名。

使用以下命令来查看数据库中文件的文档:

>db.fs.files.find()

以上命令执行后返回以下文档数据:

{   _id: ObjectId('534a811bf8b4aa4d33fdf94d'),    filename: "song.mp3",    chunkSize: 261120,    uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",   length: 10401959 }

我们可以看到 fs.chunks 集合中所有的区块,以下我们得到了文件的 _id 值,我们可以根据这个 _id 获取区块(chunk)的数据:

>db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})

以上实例中,查询返回了 40 个文档的数据,意味着mp3文件被存储在40个区块中。

MongoDB 固定集合(Capped Collections)

MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素!


创建固定集合

我们通过createCollection来创建一个固定集合,且capped选项设置为true:

>db.createCollection("cappedLogCollection",{capped:true,size:10000})

还可以指定文档个数,加上max:1000属性:

>db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})

判断集合是否为固定集合:

>db.cappedLogCollection.isCapped()

如果需要将已存在的集合转换为固定集合可以使用以下命令:

>db.runCommand({"convertToCapped":"posts",size:10000})

以上代码将我们已存在的 posts 集合转换为固定集合。


固定集合查询

固定集合文档按照插入顺序储存的,默认情况下查询就是按照插入顺序返回的,也可以使用$natural调整返回顺序。

>db.cappedLogCollection.find().sort({$natural:-1})

固定集合的功能特点

可以插入及更新,但更新不能超出collection的大小,否则更新失败,不允许删除,但是可以调用drop()删除集合中的所有行,但是drop后需要显式地重建集合。

在32位机子上一个cappped collection的最大值约为482.5M,64位上只受系统文件大小的限制。


固定集合属性及用法

属性

  • 属性1:对固定集合进行插入速度极快
  • 属性2:按照插入顺序的查询输出速度极快
  • 属性3:能够在插入最新数据时,淘汰最早的数据

用法

  • 用法1:储存日志信息
  • 用法2:缓存一些少量的文档

MongoDB 自动增长

MongoDB 没有像 SQL 一样有自动增长的功能, MongoDB 的 _id 是系统自动生成的12字节唯一标识。

但在某些情况下,我们可能需要实现 ObjectId 自动增长功能。

由于 MongoDB 没有实现这个功能,我们可以通过编程的方式来实现,以下我们将在 counters 集合中实现_id字段自动增长。


使用 counters 集合

考虑以下 products 文档。我们希望 _id 字段实现 从 1,2,3,4 到 n 的自动增长功能。

{  "_id":1,  "product_name": "Apple iPhone",  "category": "mobiles"}

为此,创建 counters 集合,序列字段值可以实现自动长:

>db.createCollection("counters")

现在我们向 counters 集合中插入以下文档,使用 productid 作为 key:

{  "_id":"productid",  "sequence_value": 0}

sequence_value 字段是序列通过自动增长后的一个值。

使用以下命令插入 counters 集合的序列文档中:

>db.counters.insert({_id:"productid",sequence_value:0})

创建 Javascript 函数

现在,我们创建函数 getNextSequenceValue 来作为序列名的输入, 指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为 productid 。

>function getNextSequenceValue(sequenceName){   var sequenceDocument = db.counters.findAndModify(      {         query:{_id: sequenceName },         update: {$inc:{sequence_value:1}},         new:true      });   return sequenceDocument.sequence_value;}

使用 Javascript 函数

接下来我们将使用 getNextSequenceValue 函数创建一个新的文档, 并设置文档 _id 自动为返回的序列值:

>db.products.insert({   "_id":getNextSequenceValue("productid"),   "product_name":"Apple iPhone",   "category":"mobiles"})>db.products.insert({   "_id":getNextSequenceValue("productid"),   "product_name":"Samsung S3",   "category":"mobiles"})

就如你所看到的,我们使用 getNextSequenceValue 函数来设置 _id 字段。

为了验证函数是否有效,我们可以使用以下命令读取文档:

>db.prodcuts.find()

以上命令将返回以下结果,我们发现 _id 字段是自增长的:

{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }

MongoDB 教程导读

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

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

让我们一起开始学习MongoDB吧!


MongoDB 的学习列表:


NoSQL 简介

NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL"。

在现代的计算系统上每天网络上都会产生庞大的数据量。

这些数据有很大一部分是由关系数据库管理系统(RDMBSs)来处理。 1970年 E.F.Codd's提出的关系模型的论文 "A relational model of data for large shared data banks",这使得数据建模和应用程序编程更加简单。

通过应用实践证明,关系模型是非常适合于客户服务器编程,远远超出预期的利益,今天它是结构化数据存储在网络和商务应用的主导技术。

NoSQL 是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。

关系型数据库遵循ACID规则

事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:

1、A (Atomicity) 原子性
原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。

比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

2、C (Consistency) 一致性
一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。

3、I (Isolation) 独立性
所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。
比如现有有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。

4、D (Durability) 持久性
持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。


分布式系统

分布式系统(distributed system)由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。

分布式系统是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。

因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。

分布式系统可以应用在在不同的平台上如:Pc、工作站、局域网和广域网上等。


分布式计算的优点

可靠性(容错) :
分布式计算系统中的一个重要的优点是可靠性。一台服务器的系统崩溃并不影响到其余的服务器。

可扩展性:
在分布式计算系统可以根据需要增加更多的机器。

资源共享:
共享数据是必不可少的应用,如银行,预订系统。

灵活性:
由于该系统是非常灵活的,它很容易安装,实施和调试新的服务。

更快的速度:
分布式计算系统可以有多台计算机的计算能力,使得它比其他系统有更快的处理速度。

开放系统:
由于它是开放的系统,本地或者远程都可以访问到该服务。

更高的性能:
相较于集中式计算机网络集群可以提供更高的性能(及更好的性价比)。


分布式计算的缺点

故障排除: :
故障排除和诊断问题。

软件:
更少的软件支持是分布式计算系统的主要缺点。

网络:
网络基础设施的问题,包括:传输问题,高负载,信息丢失等。

安全性:
开发系统的特性让分布式计算系统存在着数据的安全性和共享的风险等问题。


什么是NoSQL?

NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。

NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

为什么使用NoSQL ?

今天我们可以通过第三方平台(如:Google,Facebook等)可以很容易的访问和抓取数据。用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了, NoSQL数据库的发展也却能很好的处理这些大的数据。

web-data-image

实例

社会化关系网:

Each record: UserID1, UserID2
Separate records: UserID, first_name,last_name, age, gender,...
Task: Find all friends of friends of friends of ... friends of a given user.

Wikipedia 页面 :

Large collection of documents
Combination of structured and unstructured data
Task: Retrieve all pages regarding athletics of Summer Olympic before 1950.

RDBMS vs NoSQL

RDBMS
- 高度组织化结构化数据
- 结构化查询语言(SQL) (SQL)
- 数据和关系都存储在单独的表中。
- 数据操纵语言,数据定义语言
- 严格的一致性
- 基础事务

NoSQL
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
-键 - 值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- CAP定理
- 高性能,高可用性和可伸缩性

bigdata

NoSQL 简史

NoSQL一词最早出现于1998年,是Carlo Strozzi开发的一个轻量、开源、不提供SQL功能的关系数据库。

2009年,Last.fm的Johan Oskarsson发起了一次关于分布式开源数据库的讨论[2],来自Rackspace的Eric Evans再次提出了NoSQL的概念,这时的NoSQL主要指非关系型、分布式、不提供ACID的数据库设计模式。

2009年在亚特兰大举行的"no:sql(east)"讨论会是一个里程碑,其口号是"select fun, profit from real_world where relational=false;"。因此,对NoSQL最普遍的解释是"非关联型的",强调Key-Value Stores和文档数据库的优点,而不是单纯的反对RDBMS。


CAP定理(CAP theorem)

在计算机科学中, CAP定理(CAP theorem), 又被称作 布鲁尔定理(Brewer's theorem), 它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性(Consistency) (所有节点在同一时间具有相同的数据)
  • 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
  • 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

  • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
  • CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。
  • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
cap-theoram-image

NoSQL的优点/缺点

优点:

  • - 高可扩展性
  • - 分布式计算
  • - 低成本
  • - 架构的灵活性,半结构化数据
  • - 没有复杂的关系

缺点:

  • - 没有标准化
  • - 有限的查询功能(到目前为止)
  • - 最终一致是不直观的程序

BASE

BASE:Basically Available, Soft-state, Eventually Consistent。 由 Eric Brewer 定义。

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

BASE是NoSQL数据库通常对可用性及一致性的弱要求原则:

  • Basically Availble --基本可用
  • Soft-state --软状态/柔性事务。 "Soft state" 可以理解为"无连接"的, 而 "Hard state" 是"面向连接"的
  • Eventual Consistency --最终一致性 最终一致性, 也是是 ACID 的最终目的。

ACID vs BASE

ACID BASE
原子性(Atomicity) 基本可用(Basically Available)
一致性(Consistency) 软状态/柔性事务(Soft state)
隔离性(Isolation) 最终一致性 (Eventual consistency)
持久性 (Durable)  

NoSQL 数据库分类

类型 部分代表

特点
列存储

Hbase

Cassandra

Hypertable

顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。

文档存储

MongoDB

CouchDB

文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有有机会对某些字段建立索引,实现关系数据库的某些功能。

key-value存储

Tokyo Cabinet / Tyrant

Berkeley DB

MemcacheDB

Redis

可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)

图存储

Neo4J

FlockDB

图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。

对象存储

db4o

Versant

通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。

xml数据库

Berkeley DB XML

BaseX

高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。


谁在使用

现在已经有很多公司使用了NoSQ:
  • Google
  • Facebook
  • Mozilla
  • Adobe
  • Foursquare
  • LinkedIn
  • Digg
  • McGraw-Hill Education
  • Vermont Public Radio

什么是MongoDB ?

MongoDB 是由C++语言编写的开源数据库系统。

在高负载的情况下,添加更多的节点,可以保证服务器性能。

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

mongodb-logo

MongoDB 将数据存储为一个文档。MongoDB是一个基于分布式文件存储的数据库。

FirstName="Arun", Address="St. Xavier's Road", Spouse=[{Name:"Kiran"}], Children=[{Name:"Rihit", Age:8}].
FirstName="Sameer",Address="8 Gandhi Road".

注意:以上数据有两个不同的文档(以"."分隔)。以这种方式存储数据即为文件存储的数据库。 MongoDB是一个面向文档的数据库。



MongoDB的下载

在MongoDB官网下载该安装包,地址为:https://www.mongodb.com/try/download/community


MongoDB的特点

  • 面向集合存储,易存储对象类型的数据。
  • 模式自由
  • 支持动态查询
  • 可通过网络访问
  • 支持查询
  • 支持复制和故障恢复
  • 支持完全索引,包含内部对象
  • 文件存储格式为BSON(一种JSON的扩展)
  • 自动处理碎片,以支持云计算层次的扩展性
  • 使用高效的二进制数据存储,包括大型对象(如视频等)
  • 支持 GolangRUBYPYTHONJAVAC++PHPC# 等多种语言
  • MongoDB安装简单。


MongoDB 的发展历史

  • 2019年08月13日,MongoDB 4.2.0 发布,引入分布式事务
  • 2018年08月06日,MongoDB 4.0.2发布,支持多文档事务
  • 2017年03月17日,MongoDB 3.0.1发布
  • 2013年11月01日,MongoDB 2.4.8 发布
  • 2013年08月20日,MongoDB 2.4.6 发布
  • 2013年04月23日,MongoDB 2.4.3 发布,此版本包括了一些性能优化,功能增强以及bug修复
  • 2012年06月06日,MongoDB 2.0.6 发布,分布式文档数据库
  • 2012年05月23日,MongoDB2.1 开发分支发布了! 该版本采用全新架构,包含诸多增强

MongoDB 的语言支持

MongoDB有官方的驱动如下:



MongoDB 的适用场景

MongoDB 的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)和传统的RDBMS 系统(具有丰富的功能)之间架起一座桥梁,它集两者的优势于一身。根据官方网站的描述,Mongo 适用于以下场景。

  • 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
  • 缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo 搭建的持久化缓存层可以避免下层的数据源过载。
  • 高伸缩性的场景:Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持。
  • 用于对象及JSON 数据的存储:Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。

MongoDB 的使用也会有一些限制,例如,它不适合于以下几个地方。

  • 高度事务性的系统:例如,银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
  • 传统的商业智能应用:针对特定问题的BI 数据库会产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。
  • 需要SQL 的问题。

MongoDB 应用案例

下面列举一些公司MongoDB的实际应用:

  • Craiglist上使用MongoDB的存档数十亿条记录。
  • FourSquare,基于位置的社交网站,在Amazon EC2的服务器上使用MongoDB分享数据。
  • Shutterfly,以互联网为基础的社会和个人出版服务,使用MongoDB的各种持久性数据存储的要求。
  • bit.ly, 一个基于Web的网址缩短服务,使用MongoDB的存储自己的数据。
  • spike.com,一个MTV网络的联营公司, spike.com使用MongoDB的。
  • Intuit公司,一个为小企业和个人的软件和服务提供商,为小型企业使用MongoDB的跟踪用户的数据。
  • sourceforge.net,资源网站查找,创建和发布开源软件免费,使用MongoDB的后端存储。
  • etsy.com ,一个购买和出售手工制作物品网站,使用MongoDB。
  • 纽约时报,领先的在线新闻门户网站之一,使用MongoDB。
  • CERN,著名的粒子物理研究所,欧洲核子研究中心大型强子对撞机的数据使用MongoDB。


MongoDB 下载

MongoDB 提供了可用于 32 位和 64 位系统的预编译二进制包,你可以从 MongoDB 官网下载安装,MongoDB 预编译二进制包下载地址:

https://www.mongodb.com/try/download/community


 注意,这里选择的是zip格式的包,如果选择msi格式的包要遵循msi的安装方式。

解压安装包

下载zip包后,解压安装包,并安装它。

安装过程中,你可以通过点击 "Custom(自定义)" 按钮来设置你的安装目录。

微信截图_20200616125929

微信截图_20200616135051

下一步安装 "install mongoDB compass" 不勾选(当然你也可以选择安装它,可能需要更久的安装时间),MongoDB Compass 是一个图形界面管理工具,我们可以在后面自己到官网下载安装,下载地址:https://www.mongodb.com/download-center/compass

微信截图_20200616135217

创建数据目录

MongoDB 将数据目录存储在 db 目录下。但是这个数据目录不会主动创建,我们在安装完成后需要创建它。请注意,数据目录应该创建在根目录下((如: C: 或者 D: 等 )。

在本教程中,我们已经在 D:盘中解压了 mongodb 文件,现在让我们创建一个 data 的目录然后在 data 目录里创建db目录。

d:>cd d:d:>mkdir datad:>cd datad:data>mkdir dbd:data>cd dbd:datadb>

你也可以通过 window 的资源管理器中创建这些目录,而不一定通过命令行。


命令行下运行 MongoDB 服务器

为了从命令提示符下运行 MongoDB 服务器,你必须从 MongoDB 目录的 bin 目录中执行 mongod.exe 文件。

D://mongodbinmongod --dbpath d:datadb

如果执行成功,会输出如下信息:

2015-09-25T15:54:09.212+0800 I CONTROL  Hotfix KB2731284 or later update is notinstalled, will zero-out data files2015-09-25T15:54:09.229+0800 I JOURNAL  [initandlisten] journal dir=c:datadbjournal2015-09-25T15:54:09.237+0800 I JOURNAL  [initandlisten] recover : no journal files present, no recovery needed2015-09-25T15:54:09.290+0800 I JOURNAL  [durability] Durability thread started2015-09-25T15:54:09.294+0800 I CONTROL  [initandlisten] MongoDB starting : pid=2488 port=27017 dbpath=c:datadb 64-bit host=WIN-1VONBJOCE882015-09-25T15:54:09.296+0800 I CONTROL  [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R22015-09-25T15:54:09.298+0800 I CONTROL  [initandlisten] db version v3.0.6……

连接MongoDB

我们可以在命令窗口中运行 mongo.exe 命令即可连接上 MongoDB,执行如下命令:D:mongodbinmongo.exe

配置 MongoDB 服务

管理员模式打开命令行窗口创建目录,执行下面的语句来创建数据库和日志文件的目录
mkdir D:datadbmkdir D:datalog
创建配置文件创建一个配置文件。该文件必须设置 systemLog.path 参数,包括一些附加的配置选项更好。例如,创建一个配置文件位于 C:mongodbmongod.cfg,其中指定 systemLog.path 和 storage.dbPath。具体配置内容如下:systemLog: destination: file path: D:datalogmongod.logstorage: dbPath: D:datadb

安装 MongoDB服务

通过执行 mongod.exe,使用 --install 选项来安装服务,使用 --config 选项来指定之前创建的配置文件。D:mongodbinmongod.exe --config "D:mongodbmongod.cfg" --install

要使用备用 dbpath,可以在配置文件(例如:C:mongodbmongod.cfg)或命令行中通过 --dbpath 选项指定。

如果需要,您可以安装 mongod.exe 或 mongos.exe 的多个实例的服务。只需要通过使用 --serviceName 和 --serviceDisplayName 指定不同的实例名。只有当存在足够的系统资源和系统的设计需要这么做。

启动 MongoDB 服务

net start MongoDB

关闭 MongoDB 服务

net stop MongoDB

移除 MongoDB 服务

D:mongodbinmongod.exe --remove

MongoDB 后台管理 Shell

如果你需要进入 MongoDB 后台管理,你需要先打开 mongodb 装目录的下的bin目录,然后执行 mongo.exe 文件,MongoDB Shell 是 MongoDB 自带的交互式 Javascript shell,用来对 MongoDB 进行操作和管理的交互式环境。

当你进入 mongoDB 后台后,它默认会链接到 test 文档(数据库):

> mongoMongoDB shell version: 3.0.6connecting to: test……

由于它是一个 JavaScript shell,您可以运行一些简单的算术运算:

> 2 + 24>

db 命令用于查看当前操作的文档(数据库):

> dbtest>

插入一些简单的记录并查找它:

> db.51coolma.insert({x:10})WriteResult({ "nInserted" : 1 })> db.runoob.find(){ "_id" : ObjectId("5604ff74a274a611b0c990aa"), "x" : 10 }>

第一个命令将数字 10 插入到 51coolma 集合的 x 字段中。


Linux平台安装MongoDB


下载

MongoDB提供了linux平台上32位和64位的安装包,你可以在官网下载安装包。

安装前我们需要安装各个 Linux 平台依赖包。

Red Hat/CentOS:

sudo yum install libcurl openssl

Ubuntu 18.04 LTS ("Bionic")/Debian 10 "Buster":

sudo apt-get install libcurl4 openssl

Ubuntu 16.04 LTS ("Xenial")/Debian 9 "Stretch":

sudo apt-get install libcurl3 openssl

MongoDB 源码下载地址:https://www.mongodb.com/try/download/community


0D72BC20-1D77-437E-972C-286EB5EFB183

558D36F2-01AF-49C3-BA07-F2728B216C87

安装

这里我们选择 tgz 下载,下载完安装包,并解压 tgz(以下演示的是 64 位 Linux上的安装) 。

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz    # 下载tar -zxvf mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz                                    # 解压mv mongodb-src-r4.2.8  /usr/local/mongodb4                          # 将解压包拷贝到指定目录

MongoDB 的可执行文件位于 bin 目录下,所以可以将其添加到 PATH 路径中:

export PATH=<mongodb-install-directory>/bin:$PATH

<mongodb-install-directory> 为你 MongoDB 的安装路径。如本文的 /usr/local/mongodb4 。

export PATH=/usr/local/mongodb4/bin:$PATH

创建数据库目录

MongoDB 的数据存储在 data 目录的 db 目录下,但是这个目录在安装过程不会自动创建,所以你需要手动创建 data 目录,并在 data 目录中创建db目录。

以下实例中我们将 data 目录创建于根目录下(/)。

注意:/data/db 是 MongoDB 默认的启动的数据库路径(--dbpath)。

mkdir -p /data/db

命令行中运行 MongoDB 服务

你可以再命令行中执行mongo安装目录中的bin目录执行mongod命令来启动mongdb服务。

注意:如果你的数据库目录不是/data/db,可以通过 --dbpath 来指定。

$ ./mongod2015-09-25T16:39:50.549+0800 I JOURNAL  [initandlisten] journal dir=/data/db/journal2015-09-25T16:39:50.550+0800 I JOURNAL  [initandlisten] recover : no journal files present, no recovery needed2015-09-25T16:39:50.869+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 3.162015-09-25T16:39:51.206+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 3.522015-09-25T16:39:52.775+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 7.7 

MongoDB后台管理 Shell

如果你需要进入MongoDB后台管理,你需要先打开mongodb装目录的下的bin目录,然后执行mongo命令文件。

MongoDB Shell是MongoDB自带的交互式Javascript shell,用来对MongoDB进行操作和管理的交互式环境。

当你进入mongoDB后台后,它默认会链接到 test 文档(数据库):

$ cd /usr/local/mongodb/bin$ ./mongoMongoDB shell version: 3.0.6connecting to: testWelcome to the MongoDB shell.……

由于它是一个JavaScript shell,您可以运行一些简单的算术运算:

> 2+24> 3+69

现在让我们插入一些简单的数据,并对插入的数据进行检索:

> db.W3Cschool.insert({x:10})WriteResult({ "nInserted" : 1 })> db.W3Cschool.find(){ "_id" : ObjectId("5604ff74a274a611b0c990aa"), "x" : 10 }>

第一个命令是将数据 8 插入到w3r集合(表)的 z 字段中。



MongoDb web 用户界面

MongoDB 提供了简单的 HTTP 用户界面。 如果你想启用该功能,需要在启动的时候指定参数 --rest 。

$ ./mongod --dbpath=/data/db --rest

MongoDB 的 Web 界面访问端口比服务的端口多1000。

如果你的MongoDB运行端口使用默认的27017,你可以在端口号为28017访问web用户界面,即地址为:http://localhost:28017。

图注


MongoDB 概念解析

不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下面我们挨个介绍。

下表将帮助您更容易理解Mongo中的一些概念:

SQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段/域
indexindex索引
table joins 表连接,MongoDB不支持
primary keyprimary key主键,MongoDB自动将_id字段设置为主键

通过下图实例,我们也可以更直观的的了解Mongo中的一些概念:


数据库

一个mongodb中可以建立多个数据库。

MongoDB的默认数据库为"db",该数据库存储在data目录中。

MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

"show dbs" 命令可以显示所有数据的列表。

$ ./mongoMongoDB shell version: 3.0.6connecting to: test> show dbslocal  0.078GBtest   0.078GB> 

执行 "db" 命令可以显示当前数据库对象或集合。

$ ./mongoMongoDB shell version: 3.0.6connecting to: test> dbtest> 

运行"use"命令,可以连接到一个指定的数据库。

> use localswitched to db local> dblocal> 

以上实例命令中,"local" 是你要链接的数据库。

在下一个章节我们将详细讲解MongoDB中命令的使用。

数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串。

  • 不能是空字符串("")。
  • 不得含有' '(空格)、.、$、/、和 (空宇符)。
  • 应全部小写。
  • 最多64字节。

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

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

文档

文档是一个键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。

一个简单的文档例子如下:

{"site":"www.51coolma.cn", "name":"W3Cschool教程"}

下表列出了 RDBMS 与 MongoDB 对应的术语:

RDBMSMongoDB
数据库数据库
表格集合
文档
字段
表联合嵌入文档
主键主键 (MongoDB 提供了 key 为 _id )
数据库服务和客户端
Mysqld/Oraclemongod
mysql/sqlplusmongo

需要注意的是:

  1. 文档中的键/值对是有序的。
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB区分类型和大小写。
  4. MongoDB的文档不能有重复的键。
  5. 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

  • 键不能含有 (空字符)。这个字符用来表示键的结尾。
  • .和$有特别的意义,只有在特定环境下才能使用。
  • 以下划线"_"开头的键是保留的(不是严格要求的)。

集合

集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。

集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

比如,我们可以将以下不同数据结构的文档插入到集合中:

{"site":"www.baidu.com"}{"site":"www.google.com","name":"Google"}{"site":"www.51coolma.cn","name":"W3Cschool教程","num":5}

当第一个文档插入时,集合就会被创建。

合法的集合名

  • 集合名不能是空字符串""。
  • 集合名不能含有字符(空字符),这个字符表示集合名的结尾。
  • 集合名不能以"system."开头,这是为系统集合保留的前缀。
  • 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。 

如下实例:

db.col.findOne()

capped collections

Capped collections 就是固定大小的collection。

它有很高的性能以及队列过期的特性(过期按照插入的顺序). 有点和 "RRD" 概念类似。

Capped collections是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能 和标准的collection不同,你必须要显式的创建一个capped collection, 指定一个collection的大小,单位是字节。collection的数据存储空间值提前分配的。

要注意的是指定的存储大小包含了数据库的头信息。

db.createCollection("mycoll", {capped:true, size:100000})
  • 在capped collection中,你能添加新的对象。
  • 能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。
  • 数据库不允许进行删除。使用drop()方法删除collection所有的行。
  • 注意: 删除之后,你必须显式的重新创建这个collection。
  • 在32bit机器中,capped collection最大存储为1e9( 1X109)个字节。

元数据

数据库的信息是存储在集合中。它们使用了系统的命名空间:

dbname.system.*

在MongoDB数据库中名字空间 <dbname>.system.* 是包含多种系统信息的特殊集合(Collection),如下:

集合命名空间描述
dbname.system.namespaces列出所有名字空间。
dbname.system.indexes列出所有索引。
dbname.system.profile包含数据库概要(profile)信息。
dbname.system.users列出所有可访问数据库的用户。
dbname.local.sources包含复制对端(slave)的服务器信息和状态。

对于修改系统集合中的对象有如下限制。

在{{system.indexes}}插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)。

{{system.users}}是可修改的。 {{system.profile}}是可删除的。


MongoDB 数据类型

下表为MongoDB中常用的几种数据类型。

数据类型描述
String字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean布尔值。用于存储布尔值(真/假)。
Double双精度浮点值。用于存储浮点值。
Min/Max keys将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Arrays用于将数组或列表或多个值存储为一个键。
Timestamp时间戳。记录文档修改或添加的具体时间。
Object用于内嵌文档。
Null用于创建空值。
Symbol符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID对象 ID。用于创建文档的 ID。
Binary Data二进制数据。用于存储二进制数据。
Code代码类型。用于在文档中存储 JavaScript 代码。
Regular expression正则表达式类型。用于存储正则表达式。

MongoDB - 连接


描述

在本教程我们将讨论MongoDB的不同连接方式。


启动 MongoDB服务

在前面的教程中,我们已经讨论了如何启动MongoDB服务,你只需要在MongoDB安装目录的bin目录下执行'mongod'即可。

执行启动操作后,mongodb在输出一些必要信息后不会输出任何信息,之后就等待连接的建立,当连接被建立后,就会开始打印日志信息。

你可以使用MongoDB shell 来连接 MongoDB 服务器。你也可以使用PHP来连接mongodb。本教程我们会使用 MongoDB shell来连接Mongodb服务,之后的章节我们将会介绍如何通过php 来连接MongoDB服务。

默认情况下,MongoDB的启动端口为27017。比MongoDB启动端口大1000的端口为MongoDB的web用户界面,你可以再浏览器中输入http://localhost:28017 来访问MongoDB的web用户界面。



通过shell连接MongoDB服务

你可以通过执行以下命令来连接MongoDB的服务。

注意:localhost为主机名,这个选项是必须的:

mongodb://localhost

当你执行以上命令时,你可以看到以下输出结果:

mongodb-connect

如果你检查从哪里连接到MongoDB的服务器,您可以看到如下信息:

mongodb-connected 最后一行(标记处),打印了你成功连接上MongoDB服务的信息。

MongoDB连接命令格式

使用用户名和密码连接到MongoDB服务器,你必须使用 'username:password@hostname/dbname' 格式,'username'为用户名,'password' 为密码。

使用用户名和密码连接登陆到默认数据库:<、p>

mongodb://mongo_admin:AxB6_w3r@localhost/

以上命令中,用户 mongo_admin使用密码AxB6_w3r连接到本地的MongoDB服务上。输出结果如下所示:<、p> mongodb-connect-with-username-and-password-to-default-database

使用用户名和密码连接登陆到指定数据库:

连接到指定数据库的格式如下:

mongodb://mongo_admin:AxB6_w3r@localhost/w3r


更多连接实例

连接本地数据库服务器,端口是默认的。

mongodb://localhost

使用用户名fred,密码foobar登录localhost的admin数据库。

mongodb://fred:foobar@localhost

使用用户名fred,密码foobar登录localhost的baz数据库。

mongodb://fred:foobar@localhost/baz

连接 replica pair, 服务器1为example1.com服务器2为example2。

mongodb://example1.com:27017,example2.com:27017

连接 replica set 三台服务器 (端口 27017, 27018, 和27019):

mongodb://localhost,localhost:27018,localhost:27019

连接 replica set 三台服务器, 写入操作应用在主服务器 并且分布查询到从服务器。

mongodb://host1,host2,host3/?slaveOk=true

直接连接第一个服务器,无论是replica set一部分或者主服务器或者从服务器。

mongodb://host1,host2,host3/?connect=direct;slaveOk=true

当你的连接服务器有优先级,还需要列出所有服务器,你可以使用上述连接方式。

安全模式连接到localhost:

mongodb://localhost/?safe=true

以安全模式连接到replica set,并且等待至少两个复制服务器成功写入,超时时间设置为2秒。

mongodb://host1,host2,host3/?safe=true;w=2;wtimeoutMS=2000


参数选项说明

标准格式:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

标准的连接格式包含了多个选项(options),如下所示:

选项 描述
replicaSet=name 验证replica set的名称。 Impliesconnect=replicaSet.
slaveOk=true|false
  • true:在connect=direct模式下,驱动会连接第一台机器,即使这台服务器不是主。在connect=replicaSet模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器。
  • false: 在 connect=direct模式下,驱动会自动找寻主服务器. 在connect=replicaSet 模式下,驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器。
safe=true|false
    • true: 在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功。(还要参考 wtimeoutMS).
false: 在每次更新之后,驱动不会发送getLastError来确保更新成功。
w=n 驱动添加 { w : n } 到getLastError命令. 应用于safe=true。
wtimeoutMS=ms 驱动添加 { wtimeout : ms } 到 getlasterror 命令. 应用于 safe=true.
fsync=true|false
  • true: 驱动添加 { fsync : true } 到 getlasterror 命令.应用于 safe=true.
  • false: 驱动不会添加到getLastError命令中。
journal=true|false 如果设置wie true, 同步到 journal (在提交到数据库前写入到实体中). 应用于 safe=true
connectTimeoutMS=ms 可以打开连接的时间。
socketTimeoutMS=ms 发送和接受sockets的时间。

MongoDB 创建数据库

语法

MongoDB 创建数据库的语法格式如下:

use DATABASE_NAME

如果数据库不存在,则创建数据库,否则切换到指定数据库。

实例

以下实例我们创建了数据库 youj:

> use youjswitched to db youj> dbyouj> 

如果你想查看所有数据库,可以使用 show dbs 命令:

> show dbslocal  0.078GBtest   0.078GB> 

可以看到,我们刚创建的数据库 youj 并不在数据库的列表中,要显示它,我们需要向 youj 数据库插入一些数据。

> db.youj.insert({"name":"W3Cschool教程"})WriteResult({ "nInserted" : 1 })> show dbslocal   0.078GByouj  0.078GBtest    0.078GB> 

MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中。

MongoDB 删除数据库

语法

MongoDB 删除数据库的语法格式如下:

db.dropDatabase()

删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。

实例

以下实例我们删除了数据库 youj。

首先,查看所有数据库:

> show dbslocal   0.078GByouj  0.078GBtest    0.078GB

接下来我们切换到数据库 youj:

> use youjswitched to db youj> 

执行删除命令:

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

最后,我们再通过 show dbs 命令数据库是否删除成功:

> show dbslocal  0.078GBtest   0.078GB> 

删除集合

集合删除语法格式如下:

db.collection.drop()

MongoDB 插入文档

本章节中我们将向大家介绍如何将数据插入到MongoDB的集合中。

文档的数据结构和JSON基本一样。

所有存储在集合中的数据都是BSON格式。

BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON。

插入文档

MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下:

db.COLLECTION_NAME.insert(document)

实例

以下文档可以存储在 MongoDB 的 51coolma.cn数据库 的 col集合中:

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb', 'database', 'NoSQL'],    likes: 100})

以上实例中 col 是我们的集合名,前一章节我们已经创建过了,如果该集合不在该数据库中, MongoDB 会自动创建该集合并插入文档。

查看已插入文档:

> db.col.find(){ "_id" : ObjectId("56064886ade2f21f36b03134"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }> 

我们也可以将数据定义为一个变量,如下所示:

> document=({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb', 'database', 'NoSQL'],    likes: 100});

执行后显示结果如下:

{        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

执行插入操作:

> db.col.insert(document)WriteResult({ "nInserted" : 1 })> 

插入文档你也可以使用 db.col.save(document) 命令。如果不指定 _id 字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新该 _id 的数据。

MongoDB使用update()函数更新数据


描述

本章节我们将开始学习如何更新MongoDB中的集合数据。

MongoDB数据更新可以使用update()函数。

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

update()函数接受以下四个参数:

  • criteria : update的查询条件,类似sql update查询内where后面的。
  • objNew : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
  • upsert : 这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

在本教程中我们使用的数据库名称为"myinfo",集合名称为"userdetails",以下为插入的数据:

> document=({"user_id" : "MNOPBWN","password" :"MNOPBWN" ,"date_of_join" : "16/10/2010"
,"education" :"M.C.A." , "profession" : "CONSULTANT","interest" : "MUSIC","community_name" :["MODERN MUSIC",
"CLASSICAL MUSIC","WESTERN MUSIC"],"community_moder_id" : ["MR. BBB","MR. JJJ","MR MMM"],"community_members" :
[500,200,1500],"friends_id" : ["MMM123","NNN123","OOO123"],"ban_friends_id" :["BAN123","BAN456","BAN789"]});

> db.userdetails.insert(document)

> document=({"user_id" : "QRSTBWN","password" :"QRSTBWN" ,"date_of_join" : "17/10/2010" ,"education" :"M.B.A."
, "profession" : "MARKETING","interest" : "MUSIC","community_name" :["MODERN MUSIC", "CLASSICAL MUSIC","WESTERN
MUSIC"],"community_moder_id" : ["MR. BBB","MR. JJJ","MR MMM"],"community_members" : [500,200,1500],"friends_id" :
["MMM123","NNN123","OOO123"],"ban_friends_id" :["BAN123","BAN456","BAN789"]});

> db.userdetails.insert(document)

update() 命令

如果我们想将"userdetails"集合中"user_id"为"QRSTBWN"的"password"字段修改为"NEWPASSWORD",那么我们可以使用update()命令来实现(如下实例所示)。

如果criteria参数匹配集合中的任何一条数据,它将会执行替换命令,否则会插入一条新的数据。

以下实例将更新第一条匹配条件的数据:

> db.userdetails.update({"user_id" : "QRSTBWN"},{"user_id" : "QRSTBWN","password" :"NEWPASSWORD"
,"date_of_join" : "17/10/2010" ,"education" :"M.B.A." , "profession" : "MARKETING","interest" :
"MUSIC","community_name" :["MODERN MUSIC", "CLASSICAL MUSIC","WESTERN MUSIC"],"community_moder_id" : ["MR.
BBB","MR. JJJ","MR MMM"],"community_members" : [500,200,1500],"friends_id" : ["MMM123","NNN123","OOO123"],"ban_friends_id" :["BAN123","BAN456","BAN789"]});

update-data-into-mongodb-comand


查看集合中更新后的数据

我们可以使用以下命令查看数据是否更新:

>db.userdetails.find();

update-data-into-mongodb-view


更多实例

只更新第一条记录:

db.test0.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );

全部更新:

db.test0.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );

只添加第一条:

db.test0.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );

全部添加加进去:

db.test0.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );

全部更新:

db.test0.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );

只更新第一条记录:

db.test0.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );

MongoDB 删除文档

在前面的几个章节中我们已经学习了MongoDB中如何为集合添加数据和更新数据。在本章节中我们将继续学习MongoDB集合的删除。

MongoDB remove()函数是用来移除集合中的数据。

MongoDB数据更新可以使用update()函数。在执行remove()函数前先执行find()命令来判断执行的条件是否正确,这是一个比较好的习惯。

语法

remove() 方法的基本语法格式如下所示:

db.collection.remove(   <query>,   <justOne>)

如果你的 MongoDB 是 2.6 版本以后的,语法格式如下:

db.collection.remove(   <query>,   {     justOne: <boolean>,     writeConcern: <document>   })

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档。
  • writeConcern :(可选)抛出异常的级别。

实例

以下文档我们执行两次插入操作:

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb', 'database', 'NoSQL'],    likes: 100})

使用 find() 函数查询数据:

> db.col.find(){ "_id" : ObjectId("56066169ade2f21f36b03137"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }{ "_id" : ObjectId("5606616dade2f21f36b03138"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }

接下来我们移除 title 为 'MongoDB 教程' 的文档:

>db.col.remove({'title':'MongoDB 教程'})WriteResult({ "nRemoved" : 2 })           # 删除了两条数据>db.col.find()……                                        # 没有数据

如果你只想删除第一条找到的记录可以设置 justOne 为 1,如下所示:

>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)

如果你想删除所有数据,可以使用以下方式(类似常规 SQL 的 truncate 命令):

>db.col.remove({})>db.col.find()>

MongoDB 查询文档

语法

MongoDB 查询数据的语法格式如下:

>db.COLLECTION_NAME.find()

find() 方法以非结构化的方式来显示所有文档。

如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:

>db.col.find().pretty()

pretty() 方法以格式化的方式来显示所有文档。

实例

以下实例我们查询了集合 col 中的数据:

> db.col.find().pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

除了 find() 方法之外,还有一个 findOne() 方法,它只返回一个文档。


MongoDB 与 RDBMS Where 语句比较

如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:

操作格式范例RDBMS中的类似语句
等于{<key>:<value>}db.col.find({"by":"51coolma"}).pretty()where by = '51coolma'
小于{<key>:{$lt:<value>}}db.col.find({"likes":{$lt:50}}).pretty()where likes < 50
小于或等于{<key>:{$lte:<value>}}db.col.find({"likes":{$lte:50}}).pretty()where likes <= 50
大于{<key>:{$gt:<value>}}db.col.find({"likes":{$gt:50}}).pretty()where likes > 50
大于或等于{<key>:{$gte:<value>}}db.col.find({"likes":{$gte:50}}).pretty()where likes >= 50
不等于{<key>:{$ne:<value>}}db.col.find({"likes":{$ne:50}}).pretty()where likes != 50

MongoDB AND 条件

MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,及常规 SQL 的 AND 条件。

语法格式如下:

>db.col.find({key1:value1, key2:value2}).pretty()

实例

以下实例通过 by 和 title 键来查询 51coolma 中 MongoDB 教程 的数据

> db.col.find({"by":"51coolma", "title":"MongoDB 教程"}).pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

以上实例中类似于 WHERE 语句:WHERE by='51coolma' AND title='MongoDB 教程'


MongoDB OR 条件

MongoDB OR 条件语句使用了关键字 $or,语法格式如下:

>db.col.find(   {      $or: [	     {key1: value1}, {key2:value2}      ]   }).pretty()

实例

以下实例中,我们演示了查询键 by 值为 51coolma 或键 title 值为 MongoDB 教程 的文档。

>db.col.find({$or:[{"by":"51coolma"},{"title": "MongoDB 教程"}]}).pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}>

AND 和 OR 联合使用

以下实例演示了 AND 和 OR 联合使用,类似常规 SQL 语句为: 'where likes>50 AND (by = '51coolma' OR title = 'MongoDB 教程')'

>db.col.find({"likes": {$gt:50}, $or: [{"by": "51coolma"},{"title": "MongoDB 教程"}]}).pretty(){        "_id" : ObjectId("56063f17ade2f21f36b03133"),        "title" : "MongoDB 教程",        "description" : "MongoDB 是一个 Nosql 数据库",        "by" : "51coolma",        "url" : "http://www.51coolma.cn",        "tags" : [                "mongodb",                "database",                "NoSQL"        ],        "likes" : 100}

MongoDB 条件操作符


描述

条件操作符用于比较两个表达式并从mongoDB集合中获取数据。

在本章节中,我们将讨论如何在MongoDB中使用条件操作符。

MongoDB中条件操作符有:

  • (>) 大于 - $gt
  • (<) 小于 - $lt
  • (>=) 大于等于 - $gte
  • (<= ) 小于等于 - $lte

我们使用的数据库名称为"51coolmadb" 我们的集合名称为"col",以下为我们插入的数据。

为了方便测试,我们可以先使用以下命令清空集合 "col" 的数据:

db.col.remove({})

插入以下数据

>db.col.insert({    title: 'PHP 教程',     description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['php'],    likes: 200})

>db.col.insert({title: 'Java 教程',     description: 'Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['java'],    likes: 150})

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb'],    likes: 100})

使用find()命令查看数据:

> db.col.find(){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB (>) 大于操作符 - $gt

如果你想获取 "col" 集合中 "likes" 大于 100 的数据,你可以使用以下命令:

db.col.find({"likes" : {$gt : 100}})

类似于SQL语句:

Select * from col where likes > 100;

输出结果:

> db.col.find({"likes" : {$gt : 100}}){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }> 

MongoDB(>=)大于等于操作符 - $gte

如果你想获取"col"集合中 "likes" 大于等于 100 的数据,你可以使用以下命令:

db.col.find({likes : {$gte : 100}})

类似于SQL语句:

Select * from col where likes >=100;

输出结果:

> db.col.find({likes : {$gte : 100}}){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }> 

MongoDB (<) 小于操作符 - $lt

如果你想获取"col"集合中 "likes" 小于 150 的数据,你可以使用以下命令:

db.col.find({likes : {$lt : 150}})

类似于SQL语句:

Select * from col where likes < 150;

输出结果:

> db.col.find({likes : {$lt : 150}}){ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB (<=) 小于等于操作符 - $lte

如果你想获取"col"集合中 "likes" 小于等于 150 的数据,你可以使用以下命令:

db.col.find({likes : {$lte : 150}})

类似于SQL语句:

Select * from col where likes <= 150;

输出结果:

> db.col.find({likes : {$lte : 150}}){ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB 使用 (<) 和 (>) 查询 - $lt 和 $gt

如果你想获取"col"集合中 "likes" 大于100,小于 200 的数据,你可以使用以下命令:

db.col.find({likes : {$lt :200, $gt : 100}})

类似于SQL语句:

Select * from col where likes>100 AND  likes<200;

输出结果:

> db.col.find({likes : {$lt :200, $gt : 100}}){ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }> 

MongoDB $type 操作符

描述

在本章节中,我们将继续讨论MongoDB中条件操作符 $type。

$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。

MongoDB 中可以使用的类型如下表所示:

类型数字备注
Double1 
String2 
Object3 
Array4 
Binary data5 
Undefined6已废弃。
Object id7 
Boolean8 
Date9 
Null10 
Regular Expression11 
JavaScript13 
Symbol14 
JavaScript (with scope)15 
32-bit integer16 
Timestamp17 
64-bit integer18 
Min key255Query with -1.
Max key127 

我们使用的数据库名称为"51coolmadb" 我们的集合名称为"col",以下为我们插入的数据。

简单的集合"col":

>db.col.insert({    title: 'PHP 教程',     description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['php'],    likes: 200})

>db.col.insert({title: 'Java 教程',     description: 'Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['java'],    likes: 150})

>db.col.insert({title: 'MongoDB 教程',     description: 'MongoDB 是一个 Nosql 数据库',    by: '51coolma',    url: 'http://www.51coolma.cn',    tags: ['mongodb'],    likes: 100})

使用find()命令查看数据:

> db.col.find(){ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB 操作符 - $type 实例

如果想获取 "col" 集合中 title 为 String 的数据,你可以使用以下命令:

db.col.find({"title" : {$type : 2}})

输出结果为:

{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "php" ], "likes" : 200 }{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "java" ], "likes" : 150 }{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "51coolma", "url" : "http://www.51coolma.cn", "tags" : [ "mongodb" ], "likes" : 100 }

MongoDB Limit与Skip方法


MongoDB Limit() 方法

如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。

语法

limit()方法基本语法如下所示:

>db.COLLECTION_NAME.find().limit(NUMBER)

实例

集合 myycol 中的数据如下:

{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Tutorials Point Overview"}

以下实例为显示查询文档中的两条记录:

>db.mycol.find({},{"title":1,_id:0}).limit(2){"title":"MongoDB Overview"}{"title":"NoSQL Overview"}>

注:如果你们没有指定limit()方法中的参数则显示集合中的所有数据。


MongoDB Skip() 方法

我们除了可以使用limit()方法来读取指定数量的数据外,还可以使用skip()方法来跳过指定数量的数据,skip方法同样接受一个数字参数作为跳过的记录条数。

语法

skip() 方法脚本语法格式如下:

>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

实例

以上实例只会显示第二条文档数据

>db.mycol.find({},{"title":1,_id:0}).limit(1).skip(1){"title":"NoSQL Overview"}>

注:skip()方法默认参数为 0 。

MongoDB 排序


MongoDB sort()方法

在MongoDB中使用使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而-1是用于降序排列。

语法

sort()方法基本语法如下所示:

>db.COLLECTION_NAME.find().sort({KEY:1})

实例

col 集合中的数据如下:

{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Tutorials Point Overview"}

以下实例演示了 col 集合中的数据按字段 title 的降序排列:

>db.mycol.find({},{"title":1,_id:0}).sort({"title":-1}){"title":"Tutorials Point Overview"}{"title":"NoSQL Overview"}{"title":"MongoDB Overview"}>

注: 如果没有指定sort()方法的排序方式,默认按照文档的升序排列。

MongoDB 索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构


ensureIndex() 方法

MongoDB使用 ensureIndex() 方法来创建索引。

语法

ensureIndex()方法基本语法格式如下所示:

>db.COLLECTION_NAME.ensureIndex({KEY:1})

语法中 Key 值为你要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1即可。

实例

>db.mycol.ensureIndex({"title":1})>

ensureIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。

>db.mycol.ensureIndex({"title":1,"description":-1})>

ensureIndex() 接收可选参数,可选参数列表如下:

ParameterTypeDescription
backgroundBoolean建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false
uniqueBoolean建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
namestring索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDupsBoolean在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparseBoolean对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSecondsinteger指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
vindex version索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weightsdocument索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_languagestring对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_overridestring对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

实例

在后台创建索引:

db.values.ensureIndex({open: 1, close: 1}, {background: true})

通过在创建索引时加background:true 的选项,让创建工作在后台执行

MongoDB 聚合

MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。


aggregate() 方法

MongoDB中聚合的方法使用aggregate()。

语法

aggregate() 方法的基本语法格式如下所示:

>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

实例

集合中的数据如下:

{   _id: ObjectId(7df78ad8902c)   title: 'MongoDB Overview',    description: 'MongoDB is no sql database',   by_user: '51coolma.cn',   url: 'http://www.51coolma.cn',   tags: ['mongodb', 'database', 'NoSQL'],   likes: 100},{   _id: ObjectId(7df78ad8902d)   title: 'NoSQL Overview',    description: 'No sql database is very fast',   by_user: '51coolma.cn',   url: 'http://www.51coolma.cn',   tags: ['mongodb', 'database', 'NoSQL'],   likes: 10},{   _id: ObjectId(7df78ad8902e)   title: 'Neo4j Overview',    description: 'Neo4j is no sql database',   by_user: 'Neo4j',   url: 'http://www.neo4j.com',   tags: ['neo4j', 'database', 'NoSQL'],   likes: 750},

现在我们通过以上集合计算每个作者所写的文章数,使用aggregate()计算结果如下:

> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}]){   "result" : [      {         "_id" : "51coolma.cn",         "num_tutorial" : 2      },      {         "_id" : "Neo4j",         "num_tutorial" : 1      }   ],   "ok" : 1}>

以上实例类似sql语句: select by_user, count(*) from mycol group by by_user

在上面的例子中,我们通过字段by_user字段对数据进行分组,并计算by_user字段相同值的总和。

下表展示了一些聚合的表达式:

表达式描述实例
$sum计算总和。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg计算平均值db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min获取集合中所有文档对应值得最小值。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max获取集合中所有文档对应值得最大值。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push在结果文档中插入值到一个数组中。db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet在结果文档中插入值到一个数组中,但不创建副本。db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first根据资源文档的排序获取第一个文档数据。db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last根据资源文档的排序获取最后一个文档数据db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

管道的概念

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。

MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。

表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。

这里我们介绍一下聚合框架中常用的几个操作:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

管道操作符实例

1、$project实例

db.article.aggregate(    { $project : {        title : 1 ,        author : 1 ,    }} );

这样的话结果中就只还有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样:

db.article.aggregate(    { $project : {        _id : 0 ,        title : 1 ,        author : 1    }});

2.$match实例

db.articles.aggregate( [                        { $match : { score : { $gt : 70, $lte : 90 } } },                        { $group: { _id: null, count: { $sum: 1 } } }                       ] );

$match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。

3.$skip实例

db.article.aggregate(    { $skip : 5 });

经过$skip管道操作符处理后,前五个文档被"过滤"掉。

MongoDB 复制(副本集)

MongoDB复制是将数据同步在多个服务器的过程。

复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。

复制还允许您从硬件故障和服务中断中恢复数据。


什么是复制?

  • 保障数据的安全性
  • 数据高可用性 (24*7)
  • 灾难恢复
  • 无需停机维护(如备份,重建索引,压缩)
  • 分布式读取数据

MongoDB复制原理

mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。

mongodb各个节点常见的搭配方式为:一主一从、一主多从。

主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

MongoDB复制结构图如下所示:

MongoDB复制结构图

以上结构图总,客户端总主节点读取数据,在客户端写入数据到主节点是, 主节点与从节点进行数据交互保障数据的一致性。

副本集特征:

  • N 个节点的集群
  • 任何节点可作为主节点
  • 所有写入操作都在主节点上
  • 自动故障转移
  • 自动恢复

MongoDB副本集设置

在本教程中我们使用同一个MongoDB来做MongoDB主从的实验, 操作步骤如下:

1、关闭正在运行的MongoDB服务器。

现在我们通过指定 --replSet 选项来启动mongoDB。--replSet 基本语法格式如下:

mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"

实例

mongod --port 27017 --dbpath "D:set upmongodbdata" --replSet rs0

以上实例会启动一个名为rs0的MongoDB实例,其端口号为27017。

启动后打开命令提示框并连接上mongoDB服务。

在Mongo客户端使用命令rs.initiate()来启动一个新的副本集。

我们可以使用rs.conf()来查看副本集的配置

查看副本集姿态使用 rs.status() 命令


副本集添加成员

添加副本集的成员,我们需要使用多条服务器来启动mongo服务。进入Mongo客户端,并使用rs.add()方法来添加副本集的成员。

语法

rs.add() 命令基本语法格式如下:
>rs.add(HOST_NAME:PORT)

实例

假设你已经启动了一个名为mongod1.net,端口号为27017的Mongo服务。 在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:

>rs.add("mongod1.net:27017")>

MongoDB中你只能通过主节点将Mongo服务添加到副本集中, 判断当前运行的Mongo服务是否为主节点可以使用命令db.isMaster() 。

MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。

MongoDB 分片


分片

在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。

当MongoDB存储海量的数据时,一台机器可能不足以存储数据也足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。


为什么使用分片

  • 复制所有的写入操作到主节点
  • 延迟的敏感数据会在主节点查询
  • 单个副本集限制在12个节点
  • 当请求量巨大时会出现内存不足。
  • 本地磁盘不足
  • 垂直扩展价格昂贵

MongoDB分片

下图展示了在MongoDB中使用分片集群结构分布:

上图中主要有如下所述三个主要组件:

  • Shard:

    用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个relica set承担,防止主机单点故障

  • Config Server:

    mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。

  • Query Routers:

    前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。


分片实例

分片结构端口分布如下:

Shard Server 1:27020Shard Server 2:27021Shard Server 3:27022Shard Server 4:27023Config Server :27100Route Process:40000

步骤一:启动Shard Server

[root@100 /]# mkdir -p /www/mongoDB/shard/s0[root@100 /]# mkdir -p /www/mongoDB/shard/s1[root@100 /]# mkdir -p /www/mongoDB/shard/s2[root@100 /]# mkdir -p /www/mongoDB/shard/s3[root@100 /]# mkdir -p /www/mongoDB/shard/log[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork....[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27023 --dbpath=/www/mongoDB/shard/s3 --logpath=/www/mongoDB/shard/log/s3.log --logappend --fork

步骤二: 启动Config Server

[root@100 /]# mkdir -p /www/mongoDB/shard/config[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend --fork

注意:这里我们完全可以像启动普通mongodb服务一样启动,不需要添加—shardsvr和configsvr参数。因为这两个参数的作用就是改变启动端口的,所以我们自行指定了端口就可以。

步骤三: 启动Route Process

/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500

mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB.

步骤四: 配置Sharding

接下来,我们使用MongoDB Shell登录到mongos,添加Shard节点

[root@100 shard]# /usr/local/mongoDB/bin/mongo admin --port 40000MongoDB shell version: 2.0.7connecting to: 127.0.0.1:40000/adminmongos> db.runCommand({ addshard:"localhost:27020" }){ "shardAdded" : "shard0000", "ok" : 1 }......mongos> db.runCommand({ addshard:"localhost:27029" }){ "shardAdded" : "shard0009", "ok" : 1 }mongos> db.runCommand({ enablesharding:"test" }) #设置分片存储的数据库{ "ok" : 1 }mongos> db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}}){ "collectionsharded" : "test.log", "ok" : 1 }

步骤五: 程序代码内无需太大更改,直接按照连接普通的mongo数据库那样,将数据库连接接入接口40000

MongoDB 备份(mongodump)与恢复(mongorerstore)


MongoDB数据备份

在Mongodb中我们使用mongodump命令来备份MongoDB数据。该命令可以导出所有数据到指定目录中。

mongodump命令可以通过参数指定导出的数据量级转存的服务器。

语法

mongodump命令脚本语法如下:

>mongodump -h dbhost -d dbname -o dbdirectory
  • -h:

    MongDB所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017

  • -d:

    需要备份的数据库实例,例如:test

  • -o:

    备份的数据存放位置,例如:c:datadump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。

实例

在本地使用 27017 启动你的mongod服务。打开命令提示符窗口,进入MongoDB安装目录的bin目录输入命令mongodump:

>mongodump

执行以上命令后,客户端会连接到ip为 127.0.0.1 端口号为 27017 的MongoDB服务上,并备份所有数据到 bin/dump/ 目录中。命令输出结果如下:

MongoDB数据备份

mongodump 命令可选参数列表如下所示:

语法描述实例
mongodump --host HOST_NAME --port PORT_NUMBER该命令将备份所有MongoDB数据mongodump --host 51coolma.cn --port 27017
mongodump --dbpath DB_PATH --out BACKUP_DIRECTORY mongodump --dbpath /data/db/ --out /data/backup/
mongodump --collection COLLECTION --db DB_NAME该命令将备份指定数据库的集合。mongodump --collection mycol --db test

MongoDB数据恢复

mongodb使用 mongorerstore 命令来恢复备份的数据。

语法

mongorestore命令脚本语法如下:

>mongorestore -h dbhost -d dbname --directoryperdb dbdirectory
  • -h:

    MongoDB所在服务器地址

  • -d:

    需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2

  • --directoryperdb:

    备份数据所在位置,例如:c:datadump est,这里为什么要多加一个test,而不是备份时候的dump,读者自己查看提示吧!

  • --drop:

    恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦!

接下来我们执行以下命令:

>mongorestore

执行以上命令输出结果如下:

MongoDB数据恢复

MongoDB 监控

在你已经安装部署并允许MongoDB服务后,你必须要了解MongoDB的运行情况,并查看MongoDB的性能。这样在大流量得情况下可以很好的应对并保证MongoDB正常运作。

MongoDB中提供了mongostat 和 mongotop 两个命令来监控MongoDB的运行情况。


mongostat 命令

mongostat是mongodb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。

启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongostat命令,如下所示:

D:set upmongodbin>mongostat

以上命令输出结果如下:

mongotop 命令

mongotop也是mongodb下的一个内置工具,mongotop提供了一个方法,用来跟踪一个MongoDB的实例,查看哪些大量的时间花费在读取和写入数据。 mongotop提供每个集合的水平的统计数据。默认情况下,mongotop返回值的每一秒。

启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongotop命令,如下所示:

D:set upmongodbin>mongotop

以上命令执行输出结果如下:

带参数实例

 E:mongodb-win32-x86_64-2.2.1in>mongotop 10

后面的10是<sleeptime>参数 ,可以不使用,等待的时间长度,以秒为单位,mongotop等待调用之间。通过的默认mongotop返回数据的每一秒。

 E:mongodb-win32-x86_64-2.2.1in>mongotop --locks

报告每个数据库的锁的使用中,使用mongotop - 锁,这将产生以下输出:

输出结果字段说明:

  • ns:

    包含数据库命名空间,后者结合了数据库名称和集合。

  • db:

    包含数据库的名称。名为 . 的数据库针对全局锁定,而非特定数据库。

  • total:

    mongod花费的时间工作在这个命名空间提供总额。

  • read:

    提供了大量的时间,这mongod花费在执行读操作,在此命名空间。

  • write:

    提供这个命名空间进行写操作,这mongod花了大量的时间。

MongoDB Java

环境配置

在Java程序中如果要使用MongoDB,你需要确保已经安装了Java环境及MongoDB JDBC 驱动。

你可以参考本站的Java教程来安装Java程序。现在让我们来检测你是否安装了 MongoDB JDBC 驱动。

  • 首先你必须下载mongo jar包,下载地址:https://github.com/mongodb/mongo-java-driver/downloads, 请确保下载最新版本。
  • 你需要将mongo.jar包含在你的 classpath 中。。

连接数据库

连接数据库,你需要指定数据库名称,如果指定的数据库不存在,mongo会自动创建数据库。

连接数据库的Java代码如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   		 // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );		 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);		 System.out.println("Authentication: "+auth);      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

现在,让我们来编译运行程序并创建数据库test。

你可以更加你的实际环境改变MongoDB JDBC驱动的路径。

本实例将MongoDB JDBC启动包 mongo-2.10.1.jar 放在本地目录下:

$javac MongoDBJDBC.java$java -classpath ".:mongo-2.10.1.jar" MongoDBJDBCConnect to database successfullyAuthentication: true

如果你使用的是Window系统,你可以按以下命令来编译执行程序:

$javac MongoDBJDBC.java$java -classpath ".;mongo-2.10.1.jar" MongoDBJDBCConnect to database successfullyAuthentication: true

如果用户名及密码正确,则Authentication 的值为true。


创建集合

我们可以使用com.mongodb.DB类中的createCollection()来创建集合

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	     // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);         DBCollection coll = db.createCollection("mycol");         System.out.println("Collection created successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection created successfully

获取集合

我们可以使用com.mongodb.DBCollection类的 getCollection() 方法来获取一个集合

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	     // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);         DBCollection coll = db.createCollection("mycol");         System.out.println("Collection created successfully");         DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection created successfullyCollection mycol selected successfully

插入文档

我们可以使用com.mongodb.DBCollection类的 insert() 方法来插入一个文档

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   		 // 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         BasicDBObject doc = new BasicDBObject("title", "MongoDB").            append("description", "database").            append("likes", 100).            append("url", "//www.51coolma.cn/mongodb/").            append("by", "51coolma.cn");         coll.insert(doc);         System.out.println("Document inserted successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyDocument inserted successfully

检索所有文档

我们可以使用com.mongodb.DBCollection类中的 find() 方法来获取集合中的所有文档。

此方法返回一个游标,所以你需要遍历这个游标。

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   		// 连接到 mongodb 服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );          // 连接到数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         DBCursor cursor = coll.find();         int i=1;         while (cursor.hasNext()) {             System.out.println("Inserted Document: "+i);             System.out.println(cursor.next());             i++;         }      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyInserted Document: 1{   "_id" : ObjectId(7df78ad8902c),   "title": "MongoDB",   "description": "database",   "likes": 100,   "url": "//www.51coolma.cn/mongodb/",   "by": "51coolma.cn"}

更新文档

你可以使用 com.mongodb.DBCollection 类中的 update() 方法来更新集合中的文档。

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	 // 连接到Mongodb服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到你的数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         DBCursor cursor = coll.find();         while (cursor.hasNext()) {             DBObject updateDocument = cursor.next();            updateDocument.put("likes","200")            coll.update(updateDocument);          }         System.out.println("Document updated successfully");         cursor = coll.find();         int i=1;         while (cursor.hasNext()) {             System.out.println("Updated Document: "+i);             System.out.println(cursor.next());             i++;         }      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyDocument updated successfullyUpdated Document: 1{   "_id" : ObjectId(7df78ad8902c),   "title": "MongoDB",   "description": "database",   "likes": 200,   "url": "//www.51coolma.cn/mongodb/",   "by": "51coolma.cn"}

删除第一个文档

要删除集合中的第一个文档,首先你需要使用com.mongodb.DBCollection类中的 findOne()方法来获取第一个文档,然后使用remove 方法删除。

代码片段如下:

import com.mongodb.MongoClient;import com.mongodb.MongoException;import com.mongodb.WriteConcern;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import com.mongodb.DBCursor;import com.mongodb.ServerAddress;import java.util.Arrays;public class MongoDBJDBC{   public static void main( String args[] ){      try{   	 // 连接到Mongodb服务         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );         // 连接到你的数据库         DB db = mongoClient.getDB( "test" );	 System.out.println("Connect to database successfully");         boolean auth = db.authenticate(myUserName, myPassword);	 System.out.println("Authentication: "+auth);                  DBCollection coll = db.getCollection("mycol");         System.out.println("Collection mycol selected successfully");         DBObject myDoc = coll.findOne();         coll.remove(myDoc);         DBCursor cursor = coll.find();         int i=1;         while (cursor.hasNext()) {             System.out.println("Inserted Document: "+i);             System.out.println(cursor.next());             i++;         }         System.out.println("Document deleted successfully");      }catch(Exception e){	     System.err.println( e.getClass().getName() + ": " + e.getMessage() );	  }   }}

编译运行以上程序,输出结果如下:

Connect to database successfullyAuthentication: trueCollection mycol selected successfullyDocument deleted successfully

你还可以使用 save(), limit(), skip(), sort() 等方法来操作MongoDB数据库。

jQuery parent descendant 选择器

jQuery 选择器 jQuery 选择器

实例

选取 <div> 元素的后代的所有 <span> 元素:

$("div span")

尝试一下 »

定义和用法

("parent descendant") 选择器选取指定元素的后代的所有元素。

元素的后代可以是元素的第一代、第二代、第三代等等。


语法

("parent descendant")

参数描述
parent必需。规定要选取的父元素。
descendant必需。规定要选取的(指定父元素的)后代元素。


实例

尝试一下 - 实例

选取 <ul> 元素的后代的所有 <li> 元素
如何选取 <ul> 元素的后代的所有 <li> 元素。


jQuery 选择器 jQuery 选择器

MongoDB PHP

在php中使用mongodb你必须使用 mongodb的php驱动。

MongoDB PHP在各平台上的安装及驱动包下载请查看:PHP安装MongoDB扩展驱动

确保连接及选择一个数据库

为了确保正确连接,你需要指定数据库名,如果数据库在mongoDB中不存在,mongoDB会自动创建

代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selected

创建集合

创建集合的代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->createCollection("mycol");   echo "Collection created succsessfully";?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection created succsessfully

插入文档

在mongoDB中使用 insert() 方法插入文档:

插入文档代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";   $document = array(       "title" => "MongoDB",       "description" => "database",       "likes" => 100,      "url" => "//www.51coolma.cn/mongodb/",      "by", "51coolma.cn"   );   $collection->insert($document);   echo "Document inserted successfully";?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfullyDocument inserted successfully

查找文档

使用find() 方法来读取集合中的文档。

读取使用文档的代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";   $cursor = $collection->find();   // 迭代显示文档标题   foreach ($cursor as $document) {      echo $document["title"] . "
";   }?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfully{   "title": "MongoDB"}

更新文档

使用 update() 方法来更新文档。

以下实例将更新文档中的标题为' MongoDB Tutorial', 代码片段如下:

<pre><?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";   // 更新文档   $collection->update(array("title"=>"MongoDB"), array('$set'=>array("title"=>"MongoDB Tutorial")));   echo "Document updated successfully";   // 显示更新后的文档   $cursor = $collection->find();   // 循环显示文档标题   echo "Updated document";   foreach ($cursor as $document) {      echo $document["title"] . "
";   }?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfullyDocument updated successfullyUpdated document{   "title": "MongoDB Tutorial"}

删除文档

使用 remove() 方法来删除文档。

以下实例中我们将移除 'title' 为 'MongoDB Tutorial' 的数据记录。, 代码片段如下:

<?php    // 连接到mongodb    $m = new MongoClient();    echo "Connection to database successfully";    // 选择一个数据库    $db = $m->mydb;   echo "Database mydb selected";   $collection = $db->mycol;   echo "Collection selected succsessfully";      // 移除文档   $collection->remove(array("title"=>"MongoDB Tutorial"),false);   echo "Documents deleted successfully";      // 显示可用文档数据   $cursor = $collection->find();   // iterate cursor to display title of documents   echo "Updated document";   foreach ($cursor as $document) {      echo $document["title"] . "
";   }?>

执行以上程序,输出结果如下:

Connection to database successfullyDatabase mydb selectedCollection selected succsessfullyDocuments deleted successfully

除了以上实例外,在php中你还可以使用findOne(), save(), limit(), skip(), sort()等方法来操作Mongodb数据库。

PHP7 MongDB 安装与使用

本文教程只适合在 PHP7 的环境,如果你是 PHP5 环境,你可以参阅 PHP MongDB 安装与使用

PHP7 Mongdb 扩展安装

我们使用 pecl 命令来安装:

$ /usr/local/php7/bin/pecl install mongodb

执行成功后,会输出以下结果:

……Build process completed successfullyInstalling '/usr/local/php7/lib/php/extensions/no-debug-non-zts-20151012/mongodb.so'install ok: channel://pecl.php.net/mongodb-1.1.7configuration option "php_ini" is not set to php.ini locationYou should add "extension=mongodb.so" to php.ini

接下来我们打开 php.ini 文件,添加 extension=mongodb.so 配置。

可以直接执行以下命令来添加。

$ echo "extension=mongodb.so" >> `/usr/local/php7/bin/php --ini | grep "Loaded Configuration" | sed -e "s|.*:s*||"`

注意:以上执行的命令中 php7 的安装目录为 /usr/local/php7/,如果你安装在其他目录,需要相应修改 pecl 与 php 命令的路径。


Mongodb 使用

PHP7 连接 MongoDB 语法如下:

$manager = new MongoDBDriverManager("mongodb://localhost:27017");

插入数据

将 name 为"W3Cschool教程" 的数据插入到 test 数据库的 51coolma 集合中。

<?php$bulk = new MongoDBDriverBulkWrite;$document = ['_id' => new MongoDBBSONObjectID, 'name' => 'W3Cschool教程'];$_id= $bulk->insert($document);var_dump($_id);$manager = new MongoDBDriverManager("mongodb://localhost:27017");  $writeConcern = new MongoDBDriverWriteConcern(MongoDBDriverWriteConcern::MAJORITY, 1000);$result = $manager->executeBulkWrite('test.51coolma', $bulk, $writeConcern);?>

读取数据

这里我们将三个网址数据插入到 test 数据库的 sites 集合,并读取迭代出来:

<?php$manager = new MongoDBDriverManager("mongodb://localhost:27017");  // 插入数据$bulk = new MongoDBDriverBulkWrite;$bulk->insert(['x' => 1, 'name'=>'W3Cschool教程', 'url' => 'http://www.51coolma.cn']);$bulk->insert(['x' => 2, 'name'=>'Google', 'url' => 'http://www.google.com']);$bulk->insert(['x' => 3, 'name'=>'taobao', 'url' => 'http://www.taobao.com']);$manager->executeBulkWrite('test.sites', $bulk);$filter = ['x' => ['$gt' => 1]];$options = [    'projection' => ['_id' => 0],    'sort' => ['x' => -1],];// 查询数据$query = new MongoDBDriverQuery($filter, $options);$cursor = $manager->executeQuery('test.sites', $query);foreach ($cursor as $document) {    print_r($document);}?>

输出结果为:

stdClass Object(    [x] => 3    [name] => taobao    [url] => http://www.taobao.com)stdClass Object(    [x] => 2    [name] => Google    [url] => http://www.google.com)

更新数据

接下来我们将更新 test 数据库 sites 集合中 x 为 2 的数据:

<?php$bulk = new MongoDBDriverBulkWrite;$bulk->update(    ['x' => 2],    ['$set' => ['name' => '51coolma在线工具', 'url' => '123.51coolma.cn/webtools']],    ['multi' => false, 'upsert' => false]);$manager = new MongoDBDriverManager("mongodb://localhost:27017");  $writeConcern = new MongoDBDriverWriteConcern(MongoDBDriverWriteConcern::MAJORITY, 1000);$result = $manager->executeBulkWrite('test.sites', $bulk, $writeConcern);?>

接下来我们使用 "db.sites.find()" 命令查看数据的变化,x 为 2 的数据已经变成了51coolma在线工具:


删除数据

以下实例删除了 x 为 1 和 x 为 2的数据,注意 limit 参数的区别:

<?php$bulk = new MongoDBDriverBulkWrite;$bulk->delete(['x' => 1], ['limit' => 1]);   // limit 为 1 时,删除第一条匹配数据$bulk->delete(['x' => 2], ['limit' => 0]);   // limit 为 0 时,删除所有匹配数据$manager = new MongoDBDriverManager("mongodb://localhost:27017");  $writeConcern = new MongoDBDriverWriteConcern(MongoDBDriverWriteConcern::MAJORITY, 1000);$result = $manager->executeBulkWrite('test.sites', $bulk, $writeConcern);?>

更多使用方法请参考:http://php.net/manual/en/book.mongodb.php


MongoDB 关系

MongoDB 的关系表示多个文档之间在逻辑上的相互联系。

文档间可以通过嵌入和引用来建立联系。

MongoDB 中的关系可以是:

  • 1:1 (1对1)
  • 1: N (1对多)
  • N: 1 (多对1)
  • N: N (多对多)

接下来我们来考虑下用户与用户地址的关系。

一个用户可以有多个地址,所以是一对多的关系。

以下是 user 文档的简单结构:

{   "_id":ObjectId("52ffc33cd85242f436000001"),   "name": "Tom Hanks",   "contact": "987654321",   "dob": "01-01-1991"}

以下是 address 文档的简单结构:

{   "_id":ObjectId("52ffc4a5d85242602e000000"),   "building": "22 A, Indiana Apt",   "pincode": 123456,   "city": "Los Angeles",   "state": "California"} 

嵌入式关系

使用嵌入式方法,我们可以把用户地址嵌入到用户的文档中:

   "_id":ObjectId("52ffc33cd85242f436000001"),   "contact": "987654321",   "dob": "01-01-1991",   "name": "Tom Benzamin",   "address": [      {         "building": "22 A, Indiana Apt",         "pincode": 123456,         "city": "Los Angeles",         "state": "California"      },      {         "building": "170 A, Acropolis Apt",         "pincode": 456789,         "city": "Chicago",         "state": "Illinois"      }]} 

以上数据保存在单一的文档中,可以比较容易的获取很维护数据。 你可以这样查询用户的地址:

>db.users.findOne({"name":"Tom Benzamin"},{"address":1})

注意:以上查询中 dbusers 表示数据库和集合。

这种数据结构的缺点是,如果用户和用户地址在不断增加,数据量不断变大,会影响读写性能。

引用式关系

引用式关系是设计数据库时经常用到的方法,这种方法把用户数据文档和用户地址数据文档分开,通过引用文档的 id 字段来建立关系。

{   "_id":ObjectId("52ffc33cd85242f436000001"),   "contact": "987654321",   "dob": "01-01-1991",   "name": "Tom Benzamin",   "address_ids": [      ObjectId("52ffc4a5d85242602e000000"),      ObjectId("52ffc4a5d85242602e000001")   ]}

以上实例中,用户文档的 address_ids 字段包含用户地址的对象id(ObjectId)数组。

我们可以读取这些用户地址的对象id(ObjectId)来获取用户的详细地址信息。

这种方法需要两次查询,第一次查询用户地址的对象id(ObjectId),第二次通过查询的id获取用户的详细地址信息。

>var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})

MongoDB 数据库引用

在上一章节MongoDB关系中我们提到了MongoDB的引用来规范数据结构文档。

MongoDB 引用有两种:

  • 手动引用(Manual References)
  • DBRefs

DBRefs vs 手动引用

考虑这样的一个场景,我们在不同的集合中 (address_home, address_office, address_mailing, 等)存储不同的地址(住址,办公室地址,邮件地址等)。

这样,我们在调用不同地址时,也需要指定集合,一个文档从多个集合引用文档,我们应该使用 DBRefs。


使用 DBRefs

DBRef的形式:

{ $ref : , $id : , $db :  }

三个字段表示的意义为:

  • $ref:集合名称
  • $id:引用的id
  • $db:数据库名称,可选参数

以下实例中用户数据文档使用了 DBRef, 字段 address:

{   "_id":ObjectId("53402597d852426020000002"),   "address": {   "$ref": "address_home",   "$id": ObjectId("534009e4d852427820000002"),   "$db": "51coolmacc"},   "contact": "987654321",   "dob": "01-01-1991",   "name": "Tom Benzamin"}

address DBRef 字段指定了引用的地址文档是在 address_home 集合下的 51coolmacc 数据库,id 为 534009e4d852427820000002。

以下代码中,我们通过指定 $ref 参数(address_home 集合)来查找集合中指定id的用户地址信息:

>var user = db.users.findOne({"name":"Tom Benzamin"})>var dbRef = user.address>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})

以上实例返回了 address_home 集合中的地址数据:

{   "_id" : ObjectId("534009e4d852427820000002"),   "building" : "22 A, Indiana Apt",   "pincode" : 123456,   "city" : "Los Angeles",   "state" : "California"}

MongoDB 覆盖索引查询

官方的 MongoDB 的文档中说明,覆盖查询是以下的查询:

  • 所有的查询字段是索引的一部分
  • 所有的查询返回字段在同一个索引中

由于所有出现在查询中的字段是索引的一部分, MongoDB 无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询结果。

因为索引存在于RAM中,从索引中获取数据比通过扫描文档读取数据要快得多。


为了测试盖索引查询,使用以下 mycol 集合:

{ "_id" : 1, "name" : "tom", "sex" : "男", "score" : 100, "age" : 34 }{ "_id" : 2, "name" : "jeke", "sex" : "男", "score" : 90, "age" : 24 }{ "_id" : 3, "name" : "kite", "sex" : "女", "score" : 40, "age" : 36 }{ "_id" : 4, "name" : "herry", "sex" : "男", "score" : 90, "age" : 56 }{ "_id" : 5, "name" : "marry", "sex" : "女", "score" : 70, "age" : 18 }{ "_id" : 6, "name" : "john", "sex" : "男", "score" : 100, "age" : 31 }

我们在 mycol 集合中创建联合索引,字段为 sex 和 name :

db.mycol.ensureIndex({sex : 1, name : 1})

现在,该索引会覆盖以下查询:

db.mycol.find({sex: '男'},{name : 1, _id : 0})

 

也就是说,对于上述查询,MongoDB 的不会去数据库文件中查找。相反,它会从索引中提取数据,这是非常快速的数据查询。

由于我们的索引中不包括 _id 字段,_id 在查询中会默认返回,我们可以在 MongoDB 的查询结果集中排除它。

下面的实例没有排除 _id,查询就不会被覆盖:

db.mycol.find({sex: '男'},{name : 1})

 

最后,如果所有索引字段是一个数组,不能使用覆盖索引查询。


MongoDB 查询分析

MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。

MongoDB 查询分析常用函数有:explain() 和 hint()。


使用 explain()

explain 操作提供了查询信息,使用索引及查询统计等。有利于我们对索引的优化。

接下来我们在 users 集合中创建 gender 和 user_name 的索引:

>db.users.ensureIndex({gender:1,user_name:1})</p><p>现在在查询语句中使用 explain :</p><pre>>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()

以上的 explain() 查询返回如下结果:

{   "cursor" : "BtreeCursor gender_1_user_name_1",   "isMultiKey" : false,   "n" : 1,   "nscannedObjects" : 0,   "nscanned" : 1,   "nscannedObjectsAllPlans" : 0,   "nscannedAllPlans" : 1,   "scanAndOrder" : false,   "indexOnly" : true,   "nYields" : 0,   "nChunkSkips" : 0,   "millis" : 0,   "indexBounds" : {      "gender" : [         [            "M",            "M"         ]      ],      "user_name" : [         [            {               "$minElement" : 1            },            {               "$maxElement" : 1            }         ]      ]   }}

现在,我们看看这个结果集的字段:

  • indexOnly: 字段为 true ,表示我们使用了索引。
  • cursor:因为这个查询使用了索引,MongoDB中索引存储在B树结构中,所以这是也使用了BtreeCursor类型的游标。如果没有使用索引,游标的类型是BasicCursor。这个键还会给出你所使用的索引的名称,你通过这个名称可以查看当前数据库下的system.indexes集合(系统自动创建,由于存储索引信息,这个稍微会提到)来得到索引的详细信息。
  • n:当前查询返回的文档数量。
  • nscanned/nscannedObjects:表明当前这次查询一共扫描了集合中多少个文档,我们的目的是,让这个数值和返回文档的数量越接近越好。
  • millis:当前查询所需时间,毫秒数。
  • indexBounds:当前查询具体使用的索引。

使用 hint()

虽然MongoDB查询优化器一般工作的很不错,但是也可以使用hints来强迫MongoDB使用一个指定的索引。

这种方法某些情形下会提升性能。 一个有索引的collection并且执行一个多字段的查询(一些字段已经索引了)。

如下查询实例指定了使用 gender 和 user_name 索引字段来查询:

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})

可以使用 explain() 函数来分析以上查询:

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()

MongoDB 原子操作

mongodb不支持事务,所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。

但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。

所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况。


原子操作数据模型

考虑下面的例子,图书馆的书籍及结账信息。

实例说明了在一个相同的文档中如何确保嵌入字段关联原子操作(update:更新)的字段是同步的。

book = {          _id: 123456789,          title: "MongoDB: The Definitive Guide",          author: [ "Kristina Chodorow", "Mike Dirolf" ],          published_date: ISODate("2010-09-24"),          pages: 216,          language: "English",          publisher_id: "oreilly",          available: 3,          checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]        }

你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。

在同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:

db.books.findAndModify ( {   query: {            _id: 123456789,            available: { $gt: 0 }          },   update: {             $inc: { available: -1 },             $push: { checkout: { by: "abc", date: new Date() } }           }} )

原子操作常用命令

$set

用来指定一个键并更新键值,若键不存在并创建。

{ $set : { field : value } }

$unset

用来删除一个键。

{ $unset : { field : 1} }

$inc

$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。

{ $inc : { field : value } }

$push

用法:

{ $push : { field : value } }

把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。

$pushAll

同$push,只是一次可以追加多个值到一个数组字段内。

{ $pushAll : { field : value_array } }

$pull

从数组field内删除一个等于value值。

{ $pull : { field : _value } }

$addToSet

增加一个值到数组内,而且只有当这个值不在数组内才增加。

$pop

删除数组的第一个或最后一个元素

{ $pop : { field : 1 } }

$rename

修改字段名称

{ $rename : { old_field_name : new_field_name } }

$bit

位操作,integer类型

{$bit : { field : {and : 5}}}

偏移操作符

> t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] } > t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true ) > t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }

MongoDB 高级索引

考虑以下文档集合(users ):

{   "address": {      "city": "Los Angeles",      "state": "California",      "pincode": "123"   },   "tags": [      "music",      "cricket",      "blogs"   ],   "name": "Tom Benzamin"}

以上文档包含了 address 子文档和 tags 数组。


索引数组字段

假设我们基于标签来检索用户,为此我们需要对集合中的数组 tags 建立索引。

在数组中创建索引,需要对数组中的每个字段依次建立索引。所以在我们为数组 tags 创建索引时,会为 music、cricket、blogs三个值建立单独的索引。

使用以下命令创建数组索引:

>db.users.ensureIndex({"tags":1})

创建索引后,我们可以这样检索集合的 tags 字段:

>db.users.find({tags:"cricket"})

为了验证我们使用使用了索引,可以使用 explain 命令:

>db.users.find({tags:"cricket"}).explain()

以上命令执行结果中会显示 "cursor" : "BtreeCursor tags_1" ,则表示已经使用了索引。


索引子文档字段

假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。

为子文档的三个字段创建索引,命令如下:

>db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})

一旦创建索引,我们可以使用子文档的字段来检索数据:

>db.users.find({"address.city":"Los Angeles"})   

记住查询表达式必须遵循指定的索引的顺序。所以上面创建的索引将支持以下查询:

>db.users.find({"address.city":"Los Angeles","address.state":"California"}) 

同样支持以下查询:

>db.users.find({"address.city":"LosAngeles","address.state":"California","address.pincode":"123"})

MongoDB 索引限制


额外开销

每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果你很少对集合进行读取操作,建议不使用索引。


内存(RAM)使用

由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。

如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。


查询限制

索引不能被以下的查询使用:

  • 正则表达式及非操作符,如 $nin, $not, 等。
  • 算术运算符,如 $mod, 等。
  • $where 子句

所以,检测你的语句是否使用索引是一个好的习惯,可以用explain来查看。


索引键限制

从2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。


插入文档超过索引键限制

如果文档的索引字段值超过了索引键的限制,MongoDB不会将任何文档转换成索引的集合。与mongorestore和mongoimport工具类似。


最大范围

  • 集合中索引不能超过64个
  • 索引名的长度不能超过125个字符
  • 一个复合索引最多可以有31个字段

MongoDB ObjectId


在前面几个章节中我们已经使用了MongoDB 的对象 Id(ObjectId)。

在本章节中,我们将了解的ObjectId的结构。

ObjectId 是一个12字节 BSON 类型数据,有以下格式:

  • 前4个字节表示时间戳
  • 接下来的3个字节是机器标识码
  • 紧接的两个字节由进程id组成(PID)
  • 最后三个字节是随机数。

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。

在一个集合里面,每个集合都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。

MongoDB采用ObjectId,而不是其他比较常规的做法(比如自动增加的主键)的主要原因,因为在多个 服务器上同步自动增加主键值既费力还费时。


创建新的ObjectId

使用以下代码生成新的ObjectId:

>newObjectId = ObjectId()

上面的语句返回以下唯一生成的id:

ObjectId("5349b4ddd2781d08c09890f3")

你也可以使用生成的id来取代MongoDB自动生成的ObjectId:

>myObjectId = ObjectId("5349b4ddd2781d08c09890f4")

创建文档的时间戳

由于 ObjectId 中存储了 4 个字节的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:

>ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()

以上代码将返回 ISO 格式的文档创建时间:

ISODate("2014-04-12T21:49:17Z")

ObjectId 转换为字符串

在某些情况下,您可能需要将ObjectId转换为字符串格式。你可以使用下面的代码:

>new ObjectId.str

以上代码将返回Guid格式的字符串::

5349b4ddd2781d08c09890f3

MongoDB Map Reduce

Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。

MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。


MapReduce 命令

以下是MapReduce的基本语法:

>db.collection.mapReduce(   function() {emit(key,value);},  //map 函数   function(key,values) {return reduceFunction},   //reduce 函数   {      out: collection,      query: document,      sort: document,      limit: number   })

使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将key 与 value 传递给 Reduce 函数进行处理。

Map 函数必须调用 emit(key, value) 返回键值对。

参数说明:

  • map :映射函数 (生成键值对序列,作为 reduce 函数参数)。
  • reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。
  • out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
  • query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
  • sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
  • limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)

使用 MapReduce

考虑以下文档结构存储用户的文章,文档存储了用户的 user_name 和文章的 status字段:

{   "post_text": "51coolma.cn W3Cschool教程,最全的技术文档。",   "user_name": "mark",   "status":"active"}

现在,我们将在 posts 集合中使用 mapReduce 函数来选取已发布的文章,并通过user_name分组,计算每个用户的文章数:

>db.posts.mapReduce(    function() { emit(this.user_id,1); },    function(key, values) {return Array.sum(values)},       {           query:{status:"active"},           out:"post_total"       })

以上 mapReduce 输出结果为:

{   "result" : "post_total",   "timeMillis" : 9,   "counts" : {      "input" : 4,      "emit" : 4,      "reduce" : 2,      "output" : 2   },   "ok" : 1,}

结果表明,共有4个符合查询条件(status:"active")的文档, 在map函数中生成了4个键值对文档,最后使用reduce函数将相同的键值分为两组。

具体参数说明:

  • result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。
  • timeMillis:执行花费的时间,毫秒为单位
  • input:满足条件被发送到map函数的文档个数
  • emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
  • ouput:结果集合中的文档个数(count对调试非常有帮助)
  • ok:是否成功,成功为1
  • err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大

使用 find 操作符来查看 mapReduce 的查询结果:

>db.posts.mapReduce(    function() { emit(this.user_id,1); },    function(key, values) {return Array.sum(values)},       {           query:{status:"active"},           out:"post_total"       }).find()

以上查询显示如下结果,两个用户 tom 和 mark 有两个发布的文章:

{ "_id" : "tom", "value" : 2 }{ "_id" : "mark", "value" : 2 }

用类似的方式,MapReduce可以被用来构建大型复杂的聚合查询。

Map函数和Reduce函数可以使用 JavaScript 来实现,是的MapReduce的使用非常灵活和强大。

MongoDB 全文检索

全文检索对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。

这个过程类似于通过字典中的检索字表查字的过程。

MongoDB 从 2.4 版本开始支持全文检索,目前支持15种语言(暂时不支持中文)的全文索引。

  • danish
  • dutch
  • english
  • finnish
  • french
  • german
  • hungarian
  • italian
  • norwegian
  • portuguese
  • romanian
  • russian
  • spanish
  • swedish
  • turkish

启用全文检索

MongoDB 在 2.6 版本以后是默认开启全文检索的,如果你使用之前的版本,你需要使用以下代码来启用全文检索:

>db.adminCommand({setParameter:true,textSearchEnabled:true})

或者使用命令:

mongod --setParameter textSearchEnabled=true

创建全文索引

考虑以下 posts 集合的文档数据,包含了文章内容(post_text)及标签(tags):

{   "post_text": "enjoy the mongodb articles on 51coolma.cn",   "tags": [      "mongodb",      "51coolma"   ]}

我们可以对 post_text 字段建立全文索引,这样我们可以搜索文章内的内容:

>db.posts.ensureIndex({post_text:"text"})

使用全文索引

现在我们已经对 post_text 建立了全文索引,我们可以搜索文章中的关键词51coolma.cn:

>db.posts.find({$text:{$search:"51coolma.cn"}})

以下命令返回了如下包含51coolma.cn关键词的文档数据:

{    "_id" : ObjectId("53493d14d852429c10000002"),    "post_text" : "enjoy the mongodb articles on 51coolma.cn",    "tags" : [ "mongodb", "51coolma" ]}{   "_id" : ObjectId("53493d1fd852429c10000003"),    "post_text" : "writing tutorials on 51coolma.cn",   "tags" : [ "mongodb", "tutorial" ] }

如果你使用的是旧版本的MongoDB,你可以使用以下命令:

>db.posts.runCommand("text",{search:" 51coolma.cn"})

使用全文索引可以提高搜索效率。


删除全文索引

删除已存在的全文索引,可以使用 find 命令查找索引名:

>db.posts.getIndexes()

通过以上命令获取索引名,本例的索引名为post_text_text,执行以下命令来删除索引:

>db.posts.dropIndex("post_text_text")

MongoDB 正则表达式

正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。

许多程序设计语言都支持利用正则表达式进行字符串操作。

MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。

MongoDB使用PCRE (Perl Compatible Regular Expression) 作为正则表达式语言。

不同于全文检索,我们使用正则表达式不需要做任何配置。

考虑以下 posts 集合的文档结构,该文档包含了文章内容和标签:

{   "post_text": "enjoy the mongodb articles on tutorialspoint",   "tags": [      "mongodb",      "tutorialspoint"   ]}

使用正则表达式

以下命令使用正则表达式查找包含 51coolma.cn 字符串的文章:

>db.posts.find({post_text:{$regex:"51coolma.cn"}})

以上查询也可以写为:

>db.posts.find({post_text:/51coolma.cn/})

不区分大小写的正则表达式

如果检索需要不区分大小写,我们可以设置 $options 为 $i。

以下命令将查找不区分大小写的字符串 51coolma.cn:

>db.posts.find({post_text:{$regex:"51coolma.cn",$options:"$i"}})

集合中会返回所有包含字符串 51coolma.cn 的数据,且不区分大小写:

{   "_id" : ObjectId("53493d37d852429c10000004"),   "post_text" : "hey! this is my post on  W3Cschool.cc",    "tags" : [ "tutorialspoint" ]} 

数组元素使用正则表达式

我们还可以在数组字段中使用正则表达式来查找内容。 这在标签的实现上非常有用,如果你需要查找包含以 tutorial 开头的标签数据(tutorial 或 tutorials 或 tutorialpoint 或 tutorialphp), 你可以使用以下代码:

>db.posts.find({tags:{$regex:"tutorial"}})

优化正则表达式查询

  • 如果你的文档中字段设置了索引,那么使用索引相比于正则表达式匹配查找所有的数据查询速度更快。
  • 如果正则表达式是前缀表达式,所有匹配的数据将以指定的前缀字符串为开始。例如: 如果正则表达式为 ^tut ,查询语句将查找以 tut 为开头的字符串。

MongoDB GridFS

GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。

GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。

GridFS 可以更好的存储大于16M的文件。

GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。

GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。

每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。

以下是简单的 fs.files 集合文档:

{   "filename": "test.txt",   "chunkSize": NumberInt(261120),   "uploadDate": ISODate("2014-04-13T11:32:33.557Z"),   "md5": "7b762939321e146569b07f72c62cca4f",   "length": NumberInt(646)}

以下是简单的 fs.chunks 集合文档:

{   "files_id": ObjectId("534a75d19f54bfec8a2fe44b"),   "n": NumberInt(0),   "data": "Mongo Binary Data"}

GridFS 添加文件

现在我们使用 GridFS 的 put 命令来存储 mp3 文件。 调用 MongoDB 安装目录下bin的 mongofiles.exe工具。

打开命令提示符,进入到MongoDB的安装目录的bin目录中,找到mongofiles.exe,并输入下面的代码:

>mongofiles.exe -d gridfs put song.mp3

GridFS 是存储文件的数据名称。如果不存在该数据库,MongoDB会自动创建。Song.mp3 是音频文件名。

使用以下命令来查看数据库中文件的文档:

>db.fs.files.find()

以上命令执行后返回以下文档数据:

{   _id: ObjectId('534a811bf8b4aa4d33fdf94d'),    filename: "song.mp3",    chunkSize: 261120,    uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",   length: 10401959 }

我们可以看到 fs.chunks 集合中所有的区块,以下我们得到了文件的 _id 值,我们可以根据这个 _id 获取区块(chunk)的数据:

>db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})

以上实例中,查询返回了 40 个文档的数据,意味着mp3文件被存储在40个区块中。

MongoDB 固定集合(Capped Collections)

MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素!


创建固定集合

我们通过createCollection来创建一个固定集合,且capped选项设置为true:

>db.createCollection("cappedLogCollection",{capped:true,size:10000})

还可以指定文档个数,加上max:1000属性:

>db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})

判断集合是否为固定集合:

>db.cappedLogCollection.isCapped()

如果需要将已存在的集合转换为固定集合可以使用以下命令:

>db.runCommand({"convertToCapped":"posts",size:10000})

以上代码将我们已存在的 posts 集合转换为固定集合。


固定集合查询

固定集合文档按照插入顺序储存的,默认情况下查询就是按照插入顺序返回的,也可以使用$natural调整返回顺序。

>db.cappedLogCollection.find().sort({$natural:-1})

固定集合的功能特点

可以插入及更新,但更新不能超出collection的大小,否则更新失败,不允许删除,但是可以调用drop()删除集合中的所有行,但是drop后需要显式地重建集合。

在32位机子上一个cappped collection的最大值约为482.5M,64位上只受系统文件大小的限制。


固定集合属性及用法

属性

  • 属性1:对固定集合进行插入速度极快
  • 属性2:按照插入顺序的查询输出速度极快
  • 属性3:能够在插入最新数据时,淘汰最早的数据

用法

  • 用法1:储存日志信息
  • 用法2:缓存一些少量的文档

MongoDB 自动增长

MongoDB 没有像 SQL 一样有自动增长的功能, MongoDB 的 _id 是系统自动生成的12字节唯一标识。

但在某些情况下,我们可能需要实现 ObjectId 自动增长功能。

由于 MongoDB 没有实现这个功能,我们可以通过编程的方式来实现,以下我们将在 counters 集合中实现_id字段自动增长。


使用 counters 集合

考虑以下 products 文档。我们希望 _id 字段实现 从 1,2,3,4 到 n 的自动增长功能。

{  "_id":1,  "product_name": "Apple iPhone",  "category": "mobiles"}

为此,创建 counters 集合,序列字段值可以实现自动长:

>db.createCollection("counters")

现在我们向 counters 集合中插入以下文档,使用 productid 作为 key:

{  "_id":"productid",  "sequence_value": 0}

sequence_value 字段是序列通过自动增长后的一个值。

使用以下命令插入 counters 集合的序列文档中:

>db.counters.insert({_id:"productid",sequence_value:0})

创建 Javascript 函数

现在,我们创建函数 getNextSequenceValue 来作为序列名的输入, 指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为 productid 。

>function getNextSequenceValue(sequenceName){   var sequenceDocument = db.counters.findAndModify(      {         query:{_id: sequenceName },         update: {$inc:{sequence_value:1}},         new:true      });   return sequenceDocument.sequence_value;}

使用 Javascript 函数

接下来我们将使用 getNextSequenceValue 函数创建一个新的文档, 并设置文档 _id 自动为返回的序列值:

>db.products.insert({   "_id":getNextSequenceValue("productid"),   "product_name":"Apple iPhone",   "category":"mobiles"})>db.products.insert({   "_id":getNextSequenceValue("productid"),   "product_name":"Samsung S3",   "category":"mobiles"})

就如你所看到的,我们使用 getNextSequenceValue 函数来设置 _id 字段。

为了验证函数是否有效,我们可以使用以下命令读取文档:

>db.prodcuts.find()

以上命令将返回以下结果,我们发现 _id 字段是自增长的:

{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }

在一些版本中,MongoDB中自带了MongoDB shell(也就是mongo.exe)。在之前的教程中也有使用到该功能。但是在某些版本中MongoDB shell已经不是自带的内容,需要另外下载安装MongoDB shell,本篇文章就是解决没有mongo的问题。


初始情况

这里小编安装的是mongoDB 6.0版本。可以看到安装目录的bin目录下没有mongo.exe文件。


我们需要这个文件来连接到MongoDB数据库。所以接下来是安装内容:


下载

下载链接:https://www.mongodb.com/try/download/shell


选择Windows(MSI)版本,下载之后得到一个msi安装文件(也可以下载zip格式的,但本文以msi安装文件作为介绍)。


安装

点击msi文件即可进行安装


此处为了避免麻烦,我将其安装到MongoDB文件夹下。如果想要与前面教程兼容的话,可以安装到MongoDB的bin文件夹下。

点击next直到安装界面后点击install即可开始安装。

安装完成后会多出这几个文件:



使用

我们可以直接点击mongosh进入MongoDB shell界面,即可执行本手册中的所有操作(与mongo.exe相同)。如果将其安装到MongoDB的bin目录下,原来使用mongo.exe的启动方式是使用mongo命令,现在则改为mongosh命令。运行结果如下:


 启动时会选择连接的MongoDB,因为该shell也可以远程连接别的MongoDB,因为我们是使用本地的MongoDB数据库,所以直接点回车使用默认情况即可(默认情况即为使用本地数据库)