MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
如果对于 MongoDB的发展史感兴趣,可以参考下没有一个技术天生完美,MongoDB 十年发展全纪录这篇文章。
SQL属于/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
另外,SQL 还有一些其他的概念,对应关系如下:
SQL概念 | MongoDB概念 |
---|---|
primary key | _id |
foreign key | reference |
view | view |
index | index |
join | $lookup |
transaction | trasaction |
group by | aggregation |
MongoDB 文档可以使用 Javascript 对象表示,从格式上讲,是基于 JSON 的。
一个典型的文档如下:
{
"_id": 1,
"name" : { "first" : "John", "last" : "Backus" },
"contribs" : [ "Fortran", "ALGOL", "Backus-Naur Form", "FP" ],
"awards" : [
{
"award" : "W.W. McDowell Award",
"year" : 1967,
"by" : "IEEE Computer Society"
}, {
"award" : "Draper Prize",
"year" : 1993,
"by" : "National Academy of Engineering"
}
]
}
曾经,JSON 的出现及流行让 Web 2.0 的数据传输变得非常简单,所以使用 JSON 语法是非常容易让开发者接受的。
但是 JSON 也有自己的短板,比如无法支持像日期这样的特定数据类型,因此 MongoDB 实际上使用的是一种扩展式的JSON,叫 BSON(Binary JSON)。
BSON 所支持的数据类型包括:
分布式ID在单机时代,大多数应用可以使用数据库自增式ID 来作为主键。 传统的 RDBMS 也都支持这种方式,比如 mysql 可以通过声明 auto_increment来实现自增的主键。 但一旦数据实现了分布式存储,这种方式就不再适用了,原因就在于无法保证多个节点上的主键不出现重复。
为了实现分布式数据ID的唯一性保证,应用开发者提出了自己的方案,而大多数方案中都会将ID分段生成,如著名的 snowflake 算法中就同时使用了时间戳、机器号、进程号以及随机数来保证唯一性。
MongoDB 采用 ObjectId 来表示主键的类型,数据库中每个文档都拥有一个_id 字段表示主键。
_id 的生成规则如下:
其中包括:
值得一提的是 _id 的生成实质上是由客户端(Driver)生成的,这样可以获得更好的随机性,同时降低服务端的负载。
当然服务端也会检测写入的文档是否包含_id 字段,如果没有就生成一个。
三、操作语法除了文档模型本身,对于数据的操作命令也是基于JSON/BSON 格式的语法。
比如插入文档的操作:
db.book.insert(
{
title: "My first blog post",
published: new Date(),
tags: [ "NoSQL", "MongoDB" ],
type: "Work",
author : "James",
viewCount: 25,
commentCount: 2
}
)
执行文档查找:
db.book.find({author : "James"})
更新文档的命令:
db.book.update(
{"_id" : ObjectId("5c61301c15338f68639e6802")},
{"$inc": {"viewCount": 3} }
)
删除文档的命令:
db.book.remove({"_id":
ObjectId("5c612b2f15338f68639e67d5")})
在传统的SQL语法中,可以限定返回的字段,MongoDB可以使用Projection来表示:
db.book.find({"author": "James"},
{"_id": 1, "title": 1, "author": 1})
实现简单的分页查询:
db.book.find({})
.sort({"viewCount" : -1})
.skip(10).limit(5)
关于文档操作与 SQL方式完整的对比,官方的文档描述得比较详细:
https://docs.mongodb.com/manual/reference/sql-comparison/
MongoDB的好处挺多的,比如多列索引,查询时可以用一些统计函数,支持多条件查询,但是目前多表查询是不支持的,可以想办法通过数据冗余来解决多表查询的问题。
MongoDB对数据的操作很丰富,下面做一些举例说明,内容大部分来自官方文档。
查询colls所有数据
db.colls.find()
//select * from colls
通过指定条件查询
db.colls.find({‘last_name’: ‘Smith’});
//select * from colls where last_name=’Smith’
指定多条件查询
db.colls.find( { x : 3, y : “foo” } );
//select * from colls where x=3 and y=’foo’
指定条件范围查询
db.colls.find({j: {$ne: 3}, k: {$gt: 10} });
//select * from colls where j!=3 and k>10
查询不包括某内容
db.colls.find({}, {a:0});
//查询除a为0外的所有数据
支持 <, , >=
查询,需用符号替代分别为$lt,$lte,$gt,$gte
db.colls.find({ “field” : { $gt: value } } );
db.colls.find({ “field” : { $lt: value } } );
db.colls.find({ “field” : { $gte: value } } );
db.colls.find({ “field” : { $lte: value } } );
也可对某一字段做范围查询
db.colls.find({ “field” : { $gt: value1, $lt: value2 } } );
不等于查询用字符$ne
db.colls.find( { x : { $ne : 3 } } );
in查询用字符$in
db.colls.find( { “field” : { $in : array } } );
db.colls.find({j:{$in: [2,4,6]}});
not in查询用字符$nin
db.colls.find({j:{$nin: [2,4,6]}});
取模查询用字符$mod
db.colls.find( { a : { $mod : [ 10 , 1 ] } } )
// where a % 10 == 1
$all查询
db.colls.find( { a: { $all: [ 2, 3 ] } } );
//指定a满足数组中任意值时
$size查询
db.colls.find( { a : { $size: 1 } } );
//对对象的数量查询,此查询查询a的子对象数目为1的记录
$exists查询
db.colls.find( { a : { $exists : true } } );
// 存在a对象的数据
db.colls.find( { a : { $exists : false } } );
// 不存在a对象的数据
$type
查询$type
值为bson数据的类型值
db.colls.find( { a : { $type : 2 } } );
// 匹配a为string类型数据
db.colls.find( { a : { $type : 16 } } );
// 匹配a为int类型数据
使用正则表达式匹配
db.colls.find( { name : /acme.*corp/i } );
//类似于SQL中like
内嵌对象查询
db.colls.find( { “author.name” : “joe” } );
1.3.3版本及更高版本包含$not查询
db.colls.find( { name : { $not : /acme.*corp/i } } );
db.colls.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
sort()排序
db.colls.find().sort( { ts : -1 } );
//1为升序2为降序
limit()对限制查询数据返回个数
db.colls.find().limit(10)
skip()跳过某些数据
db.colls.find().skip(10)
snapshot()快照保证没有重复数据返回或对象丢失
count()统计查询对象个数
db.students.find({‘address.state’ : ‘CA’}).count();
//效率较高
db.students.find({‘address.state’ : ‘CA’}).toArray().length;
//效率很低
group()对查询结果分组和SQL中group by函数类似
distinct()返回不重复值
四、索引无疑,索引是一个数据库的关键能力,MongoDB 支持非常丰富的索引类型。利用这些索引,可以实现快速的数据查找,而索引的类型和特性则是针对不同的应用场景设计的。
索引的技术实现依赖于底层的存储引擎,在当前的版本中 MongoDB 使用 wiredTiger 作为默认的引擎。
在索引的实现上使用了 B+树的结构,这与其他的传统数据库并没有什么不同。
所以这是个好消息,大部分基于SQL数据库的一些索引调优技巧在 MongoDB 上仍然是可行的。
使用 ensureIndexes 可以为集合声明一个普通的索引:
db.book.ensureIndex({author: 1})
author后面的数字 1 代表升序,如果是降序则是 -1
实现复合式(compound)的索引,如下:
db.book.ensureIndex({type: 1, published: 1})
只有对于复合式索引时,索引键的顺序才变得有意义
如果索引的字段是数组类型,该索引就自动成为数组(multikey)索引:
db.book.ensureIndex({tags: 1})
MongoDB 可以在复合索引上包含数组的字段,但最多只能包含一个
索引特性
在声明索引时,还可以通过一些参数化选项来为索引赋予一定的特性,包括:
unique=true,表示一个唯一性索引 expireAfterSeconds=3600,表示这是一个TTL索引,并且数据将在1小时后老化 sparse=true,表示稀疏的索引,仅索引非空(non-null)字段的文档 partialFilterExpression: { rating: { $gt: 5 },条件式索引,即满足计算条件的文档才进行索引索引分类
除了普通索引之外,MongoDB 支持的类型还包括:
哈希(HASH)索引,哈希是另一种快速检索的数据结构,MongoDB 的 HASH 类型分片键会使用哈希索引。 地理空间索引,用于支持快速的地理空间查询,如寻找附近1公里的商家。 文本索引,用于支持快速的全文检索 模糊索引(Wildcard Index),一种基于匹配规则的灵活式索引,在4.2版本开始引入。索引评估、调优
使用 explain() 命令可以用于查询计划分析,进一步评估索引的效果。
如下:
> db.test.explain().find( { a : 5 } )
{
"queryPlanner" : {
...
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"a" : 5
},
"indexName" : "a_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {"a" : ["[5.0, 5.0]"]}
}
}},
...
}
从结果 winningPlan 中可以看出执行计划是否高效,比如:
未能命中索引的结果,会显示COLLSCAN 命中索引的结果,使用IXSCAN 出现了内存排序,显示为 SORT Referencehttps://www.cnblogs.com/littleatp/p/11675233.html