MongoDB笔记

MongoDB

皆来自“菜鸟教程”

概念解析

可以类比elasticsearch

sqlmongodb说明
databasedatabase数据库
tablecollection数据表 / 集合
rowdocument行 / 文档
columnfield列 / 域
indexindex索引
primary keyprimary key主键(MongoDB自动将_id字段设置为主键)
Mysqldmongod数据库服务
mysqlmongo客户端

数据库

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

show dbs 命令可以显示所有数据的列表。
db显示当前数据库对象或集合
use连接到一个指定的数据库

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

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

集合

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

合法的集合名

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

capped collections
Capped collections 就是固定大小的collection。

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

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

Capped collections 可以按照文档的插入顺序保存到集合中,而且这些文档在磁盘上存放位置也是按照插入顺序来保存的,所以当我们更新Capped collections 中文档的时候,更新后的文档不可以超过之前文档的大小,这样话就可以确保所有文档在磁盘上的位置一直保持不变。

由于 Capped collection 是按照文档的插入顺序而不是使用索引确定插入位置,这样的话可以提高增添数据的效率。(MongoDB 的操作日志文件 oplog.rs 就是利用 Capped Collection 来实现的。)

要注意的是指定的存储大小包含了数据库的头信息。
db.createCollection("mycoll", {capped:true, size:100000})

  • 在 capped collection 中,你能添加新的对象。
  • 能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。
  • 使用 Capped Collection 不能删除一个文档,可以使用 drop() 方法删除 collection 所有的行。
  • 删除之后,你必须显式的重新创建这个 collection。

文档

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

需要注意的是:

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

文档键命名规范:

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

元数据

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

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

集合命名空间描述
dbname.system.namespaces列出所有名字空间
dbname.system.indexes列出所有索引(可以创建索引。但除此之外该表信息是不可变的)
dbname.system.profile包含数据库概要(profile)信息(可删除)
dbname.system.users列出所有可访问数据库的用户(可修改)
dbname.local.sources包含复制对端(slave)的服务器信息和状态

数据类型

数据类型描述
String字符串,UTF-8 编码的字符串才是合法的
Integer整型数值
Boolean布尔值
Double双精度浮点值
Min/Max keys将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比
Array用于将数组或列表或多个值存储为一个键
Timestamp时间戳
Object用于内嵌文档
Null用于创建空值
Symbol符号。基本上等同于字符串类型,但它一般用于采用特殊符号类型的语言
Date日期时间
Object ID对象 ID。用于创建文档的 ID
Binary Data二进制数据
Code代码类型。用于在文档中存储 JavaScript 代码
Regular expression正则表达式类型。用于存储正则表达式

ObjectId
ObjectId 类似唯一主键,可以很快的去生成和排序
MongoDB 中存储的文档必须有一个 _id 键。这个键的值可以是任何类型的,默认是个 ObjectId 对象

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

> var newObject = ObjectId()
> newObject.getTimestamp()
ISODate(“2017-11-25T07:21:10Z”)

ObjectId 转为字符串

> newObject.str
5a1919e63df83ce79df8b38f

命令

连接:mongodb://[username:password@]host[:port][,host:port2, ...][ /[database][?options] ]
(?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过 & 或 ; 隔开)
具体连接选项:https://www.runoob.com/mongodb/mongodb-connections.html

操作数据库

创建:use (如果数据库不存在,则创建数据库,否则切换到指定数据库)

查看所有数据库:show dbs

查看当前数据库:db

删除当前数据库:db.dropDatabase()

操作集合

在 MongoDB 中,你不需要刻意创建集合。当你插入一些文档时,MongoDB 会自动创建集合。
创建:db.createCollection(name [, options])
例:创建集合hellodb.createCollection("hello")
options:

  • capped(布尔类型) 如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。

  • size(数值类型) 为固定集合指定一个最大值,即字节数。如果 capped 为 true,必须要指定该字段。

  • max(数值类型) 指定固定集合中包含文档的最大数量。

查看所有集合show collections

删除集合db.collection_name.drop()
例:删除集合abcdb.abc.drop()

操作文档

文档的数据结构和 JSON 基本一样。
.
所有存储在集合中的数据都是 BSON 格式。
.
BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。

插入insert() 或 insertOne() 或 insertMany()

insert()
作用: 若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据

格式:db.COLLECTION_NAME.insert(document)

例:在当前数据库下的 col 集合中插入一个文档

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

insertOne()
作用:如果 _id 主键存在则更新数据,如果不存在就插入数据

格式:db.collection_name.insertOne(<document> [,{writeConcern: <document>}] )
writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。

insertMany()
作用:插入多条数据

格式:

db.collection.insertMany(
   [ <document1> , <document2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。
ordered:指定是否按顺序写入,默认 true,按顺序写入。


更新update()

格式:

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

例:更新 ‘title’ 为 ‘MongoDB 教程’ 的第一个文档的 ‘title’ 为 ‘MongoDB’
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})


在执行 remove() 函数前先执行 find() 命令来判断执行的条件是否正确,这是一个比较好的习惯

删除remove()

格式

db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>
   }
)
  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
  • writeConcern :(可选)抛出异常的级别。

查询find() findOne()

格式:db.collection.find(query, projection)

  • query :可选,使用查询操作符指定查询条件
  • projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
  • db.collection.find().pretty() :以易读的方式来读取数据

条件操作符

在这里插入图片描述

等于			(默认)		{<key>:<value>}
小于			($lt{<key>:{$lt:<value>}}
小于或等于	($lte{<key>:{<$lte:<value>}}
大于			($gt{<key>:{$gt:<value>}}
大于或等于	($gte{<key>:{$gte:<value>}}
不等于		($ne{<key>:{$ne:<value>}}

and

{key1:value1, key2:value2}

or

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

{$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}
// where by = "菜鸟教程" or title = "MongoDB 教程"

and 和 or 一起使用

db.col.find({
	"likes": {$gt:50}, 
	$or: [
		{"by": "菜鸟教程"},
		{"title": "MongoDB 教程"}
	]
}).pretty()
// where likes>50 AND (by = '菜鸟教程' OR title = 'MongoDB 教程')

type
例:获取 “col” 集合中 title 为 String 类型的数据

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

读取指定数量的数据 limit()

格式:db.COLLECTION_NAME.find().limit(NUMBER)

跳过指定数量的数据 skip()

格式:db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

排序 sort()

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

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

例:db.col.find({},{"title":1}).sort({"likes":-1})

操作索引

创建:createIndex()
格式:db.collection.createIndex(keys, options)
keys:{要创建索引的字段: 1 / -1 [,要创建…字段: 1 / -1, …] }
例:db.col.createIndex({"title":1,"description":-1})
options:如下图
在这里插入图片描述
查看集合索引db.col.getIndexes()

查看集合索引大小db.col.totalIndexSize()

删除集合所有索引db.col.dropIndexes()

删除集合指定索引db.col.dropIndex("索引名称")

聚合 aggregate()

聚合的概念:MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果


管道的概念
管道在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各个节点常见的搭配方式为:一主一从、一主多从。

主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
在这里插入图片描述
副本集特征:

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

副本集设置

  1. 以–replSet启动MongoDB服务器
    mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
    – replSet 指定MongoDB实例的名字

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

> rs.initiate( 
	{
		_id: 'rs0', 
		members: [
			{_id: 0, host: 'localhost:27020'},
			{_id: 1, host: 'localhost:27021'}
		 ]
	 }
 ) 
> rs.isMaster() #查看主从关系
  1. 添加副本集成员 rs.add(HOST_NAME:PORT)
    假设你已经启动了一个名为mongod1.net,端口号为27017的Mongo服务。
    在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:
    rs.add("mongod1.net:27017")

rs.conf() 查看副本集的配置

rs.status() 查看副本集状态

rs.isMaster() 查看主从关系

分片

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


为什么分片:

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

在这里插入图片描述

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

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

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


测试:
启动多个服务器:

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

前端路由的启动

/usr/local/mongoDB/bin/mongos
–port 40000 // 指定前端路由的端口
–configdb localhost:27100 // 指定config服务器
–fork
–logpath=/www/mongoDB/shard/log/route.log
–chunkSize 500 // 指定chunk的大小的,单位是MB,默认大小为200MB.

配置sharding(添加shard节点)

// 进入router服务器
[root@100 shard]# /usr/local/mongoDB/bin/mongo admin --port 40000
MongoDB shell version: 2.0.7
connecting to: 127.0.0.1:40000/admin

// 添加shard节点
mongos> 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 }

备份与恢复

备份
mongodump -h dbhost -d dbname -o dbdirectory

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

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

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

  • –collection --db:备份指定数据库的指定集合

  • –dbpath DB_PATH --out BACKUP_DIRECTORY:复制数据库


恢复
mongorestore -h <hostname><:port> -d dbname <path>

  • –host <:port>, -h <:port>:
    MongoDB所在服务器地址,默认为: localhost:27017

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

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

  • <path>:
    mongorestore 最后的一个参数,设置备份数据所在位置,例如:c:\data\dump\test。
    你不能同时指定 <path> 和 --dir 选项,–dir也可以设置备份目录。

  • –dir:
    指定备份的目录
    你不能同时指定 <path> 和 --dir 选项。

监控

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

mongotop <num>

mongotop输出结果字段说明:

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

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

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

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

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

JDBC

导入依赖:

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>3.12.11</version>
</dependency>

步骤:

// 连接服务器,默认host为localhost,port为27017
MongoClient mongoClient = new MongoClient();

// 连接数据库
MongoDatabase database = mongoClient.getDatabase("mytest");

// 创建集合
database.createCollection("col");

// 获取集合
MongoCollection<Document> collection = database.getCollection("col");

// 插入文档
Document document = new Document("title", "hello").
        append("name", "world").
        append("age", 1);
collection.insertOne(document);

// 获取文档
FindIterable<Document> documents = collection.find();
MongoCursor<Document> iterator = documents.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

// 更新文档
collection.updateOne(Filters.eq("age", 1), new Document("$set", new Document("age", 10)));

// 删除文档
collection.deleteOne(Filters.eq("age", 10));

如果你的 Mongo 需要验证用户名及密码,可以使用以下代码

//连接到MongoDB服务 如果是远程连接可以替换“localhost”为服务器所在IP地址  
//ServerAddress()两个参数分别为 服务器地址 和 端口  
ServerAddress serverAddress = new ServerAddress("localhost",27017);  
List<ServerAddress> addrs = new ArrayList<ServerAddress>();  
addrs.add(serverAddress);  
  
//MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码  
MongoCredential credential = MongoCredential.createScramSha1Credential("username", "databaseName", "password".toCharArray());  
List<MongoCredential> credentials = new ArrayList<MongoCredential>();  
credentials.add(credential);  
  
//通过连接认证获取MongoDB连接  
MongoClient mongoClient = new MongoClient(addrs,credentials);

整合springboot

导入依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

编写配置文件

spring.data.mongodb.uri=mongodb://localhost:27017/mytest

编写实体类

@Data
@Document("User") // 可以指定集合名,若不指定则为首字母小写类名user
public class User {
    @Id
    private int id;
    private String name;
    private int age;
}

注入MongoTemplate
insertremoveupsertfind

例:

@Test
void find(){
    Query query = new Query(Criteria.where("_id").gt(1).and("age").is(100));
//   query.addCriteria(Criteria.where("_id").is(1));
    
    // 排序
    query.with(Sort.by(Sort.Direction.ASC, "name"));
    // 分页
    int pageSize = 10;
    int pageNow = 1;
    long count = mongoTemplate.count(query, User.class);
    query.skip((pageNow - 1) * 10).limit(pageSize);
    //
    List<User> userList = mongoTemplate.find(query, User.class);
    userList.forEach(System.out::println);
}

@Test
void update(){
    Query query = new Query(Criteria.where("name").is("czc").orOperator(Criteria.where("age").is(2)));
    Update update = new Update();
    update.set("name", "czc1").set("age", 20);
    mongoTemplate.upsert(query, update, User.class);
}

文档的引用式关系

手动引用
这种方法把用户数据文档和用户地址数据文档分开,通过引用文档的 id 字段来建立关系

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

DBRefs

{
   "_id":ObjectId("53402597d852426020000002"),
   "address": {
	   "$ref": "address_home",
	   "$id": ObjectId("534009e4d852427820000002"),
	   "$db": "runoob"
   },
   "contact": "987654321",
   "dob": "01-01-1991",
   "name": "Tom Benzamin"
}
  • $ref:集合名称
  • $id:引用的id
  • $db:数据库名称,可选参数

查询分析 explain()

db.users.find({gender:"M"},{user_name:1,_id:0}).explain()
结果集的字段解释:

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

指定索引查询 hint()

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

原子操作

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


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

{ $set : { field : value } }

$unset
用来删除一个键。

{ $unset : { field : 1} }

$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 } ] }

索引限制

索引会有额外开销

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

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

最大范围

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

ObjectId

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。
.
在一个集合里面,每个文档都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。
.
MongoDB采用ObjectId,而不是其他比较常规的做法(比如自动增加的主键)的主要原因,因为在多个 服务器上同步自动增加主键值既费力还费时。

Map Reduce

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

基本语法:

>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的用处不大)
    在这里插入图片描述

输出结果:

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

具体参数说明:

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

GridFS

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

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

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

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

添加
mongofiles.exe -d gridfs put song.mp3
-d gridfs 指定存储文件的数据库名称,如果不存在该数据库,MongoDB会自动创建

查看

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

> db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})
以上实例中,查询返回了 40 个文档的数据,意味着mp3文件被存储在40个区块中。

固定集合(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})

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

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

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

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


固定集合属性及用法

  • 属性
    • 属性1:对固定集合进行插入速度极快
    • 属性2:按照插入顺序的查询输出速度极快
    • 属性3:能够在插入最新数据时,淘汰最早的数据
  • 用法
    • 用法1:储存日志信息
    • 用法2:缓存一些少量的文档

版权声明:本文为weixin_52757736原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。