Mongo是NoSql数据库的一种,与传统的关系型数据库不论是存储结构还是具体语法上都有很大的差异。
本文的目标是以初学者视角,概述下MongoDB的一些概念与语法。
一、概述
MongDB与传统的关系型数据库最大区别是存储上,以Collections(集合)的概念将一类Document汇聚在一起。类比与传统的关系型数据库,可以将Collections类比为表空间,Document类比为每一条记录。其中Document以Json格式存储数据,每一个document都存储有一个完整的Json,同时Json内的结构不定,每一个document都可以有不同的结构。至于后续的底层存储结构,这里不做赘述,在后续的文章中再做详解。
二、应用语法
章节分为增删改查四个部分记录。
1、增
(1)创建数据库
use DATABASE_NAME;
该命令为创建数据库,若已存在数据库,则进入相应数据库。
注:根据官方文档,是需要在执行collection.insert才会创建,这里后续补充;
(2)创建集合
db.createCollection("zyl_test");
这就类似于关系型数据库中创建了一张表,在mongo中实际是创建了一块存储空间。与关系型数据库不同的是,这里不需要定义出表结构,具体的结构在Document中指定。
db.createCollection(name, options)
同时这个方法第二参数options可以用来指定内存大小与索引选项。
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔 | (可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 当该值为 true 时,必须指定 size 参数。 |
autoIndexId | 布尔 | (可选)如为 true,自动在 _id 字段创建索引。默认为 false。 |
size | 数值 | (可选)为固定集合指定一个最大值(以字节计)。 如果 capped 为 true,也需要指定该字段。 |
max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
在插入文档时,MongoDB 首先检查固定集合的 size 字段,然后检查 max 字段。
(3)插入Document
1)单条插入:db.zyl_test.insertOne({"name":"zyl"})
2)批量插入:db.zyl_test.insertMany([{"name":"ddd","sex":"f","Country":"China"},{"name":"eee","sex":"f","Country":"China"}]);
3)插入:db.zyl_test.insert({"name":"zyl"})/db.zyl_test.insert([{"name":"kkk","sex":"f","Country":"USA","age":"20"},{"name":"lll","sex":"f","Country":"USA","age":"20"}])(这个实际上就兼顾了1、2两者)
2、删
(1)删除数据库
db.dropDatabase("zyl_test")
(2)删除Collection
db.collection.drop("zyl_test")
(3)删除Document
db.collection.remove( <query>, <justOne> )
remove后可接两个参数,query为条件,justone为限制条件
db.zyl_test.remove(
{"name":"zyl"},2
)
justOne只要有值就默认删除一条数据,所以这里的2和1实际等价。
2.6版本以后语法略有变动。
db.collection.remove( <query>, { justOne: <boolean>, writeConcern: <document> } )
3、改
修改Document
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 :可选,抛出异常的级别。
db.zyl_test.update(
{"name":"fff"},
{$set:{"sex":"s"}}
);
这里需要注意$set,指定的话就是更新相应字段;不指定则会将<update>内容替换至符合<query>条件的document。
4、查
1)查询语法
db.collection.find(query, projection)
- query :可选,使用查询操作符指定查询条件
- projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
db.zyl_test.find({"name":"dsy","sex":"f"});
查询结果:
如果需要实现模糊查询,需要在相应属性后接正则表达式,而不是直接限定字符串。
补:还有一些常用的api
.skip():跳过查询结果集中前多少个Document;
.limit():限制展示多少条数据;(与前一个连用可以实现分页查询)
.sort():排序,-1降序排列,1升序排列。
start = 1;
size = 5;
db.zyl_test.find().skip((start-1)*size).limit(size).sort({"age":-1});
上面实现了按照age倒序的分页展示。
2)聚合函数
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
下表展示了一些聚合的表达式:
表达式 | 描述 | 实例 |
---|---|---|
$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:输出接近某一地理位置的有序文档。
示例:
db.zyl_test.aggregate([{$group:{_id:{"name":"$name","age":"$age"},"num":{$sum:1}}}])
这样可以查询出按照name和age分组的数据,并计算个数。
类似于关系型数据库的下列sql:
select * from name,age,count(1) from zyl_test group by name,age;
补充:
操作符:
$gt -------- greater than > $gte --------- gt equal >= $lt -------- less than < $lte --------- lt equal <= $ne ----------- not equal != $eq -------- equal =