MongoDB01

服务器三种架构

服务器集群就是指将很多服务器集中起来一起进行同一种服务,在客户端看来就像是只有一个服务器。集群可以利用多个计算机进行并行计算从而获得很高的计算速度,也可以用多个计算机做备份,从而使得任何一个机器坏了整个系统还是能正常运行。

负载均衡 (Load Balancing) 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

所谓分布式资源共享服务器就是指数据和程序可以不位于一个服务器上,而是分散到多个服务器,以网络上分散分布的地理信息数据及受其影响的数据库操作为研究对象的一种理论计算模型服务器形式。分布式有利于任务在整个计算机系统上进行分配与优化,克服了传统集中式系统会导致中心主机资源紧张与响应瓶颈的缺陷,解决了网络GIS 中存在的数据异构、数据共享、运算复杂等问题,是地理信息系统技术的一大进步。

总之

三种架构都是常见的服务器架构,集群的主要是IT公司在做,可以保障重要数据安全;负载均衡主要是为了分担访问量,避免临时的网络堵塞,主要用于电子商务类型的网站;分布式服务器主要是解决跨区域,多个单个节点达到高速访问的目前,一般是类似CDN的用途的话,会采用分布式服务器。

1
2
3
4
5
6
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
一个mongodb中可以建立多个数据库。MongoDB的默认数据库为"db",该数据库存储在data目录中。MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
mongodb的数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,这样提高查询效率,所谓内存数据映射,所以
mongodb本身很吃内存。不过MongoDB3.0版本以后会好很多。

mongodb、redis和mysql

存储

mysql数据是存在硬盘的,读的时候也肯定是要读到内存的,取数据都是读到内存才取的。而PL/sql的一些语句则不一定存到数据库,像游标,变量等

mongodb的数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,这样提高查询效率,所谓内存数据映射,所以mongodb本身很吃内存,不过3.0版本以后会好很多

redis是一个内存数据库, 所有数据基本上都存在于内存当中, 会定时以追加或者快照的方式刷新到硬盘中. 由于redis是一个内存数据库, 所以读取写入的速度是非常快的, 所以经常被用来做数据, 页面等的缓存。

mongodb、redis区别

就Redis和MongoDB来说,一般称之为Redis缓存、MongoDB数据库。这也是有道有理有根据的,

Redis主要把数据存储在内存中,其“缓存”的性质远大于其“数据存储“的性质,其中数据的增删改查也只是像变量操作一样简单;

MongoDB却是一个“存储数据”的系统,增删改查可以添加很多条件,就像SQL数据库一样灵活,这一点在面试的时候很受用。MongoDB从一开始就设计用来作为分布式数据库,处理多个节点是一个核心要求

docker中登陆链接mongodb

1
2
3
4
5
6
7
8
9
10
11
12
$winpty docker exec -it docker_mongo_1 sh  //登陆容器
# mongo -u root -p 123456 链接mongo
>show dbs //查看已有数据库
> db //登录mongodb不指定数据库默认进入test库
test
>use mam //切换数据库到mam(或者创建数据库,需有表数据才能显示在navicat)
>show collections //查看当前数据中的数据集合(相当于关系型数据库中的表)
>db.stats()查看当前数据库,状态
>db.dropDatabase()删除当前数据库

>db.goods.remove({});清空所有的数据:
>db.表.update({条件},{‘$unset’:{字段:1/字段:0}}) 删除字段

MongoDB语法与现有关系型数据库SQL语法比较

1
2
3
4
5
6
7
8
9
10
11
12
$lt $lte $gt $gte $ne分别表示为:< 、 <= 、 > 、 >=,!=通常组合使用,例如:db.user.find({"age":{"$gte":18,"$lte":25}})
$in:[] in查询 $nin(不在里面) $all 符合[]里面元素条件就可以 显示数据
$set 更新字段,只修改设置的字段,其他字段不变化,没有$set的修改:只修改设置的字段,没有修改的字段就删除了(除了_id字段)
$inc 字段+
$regex 模糊查询
$match用于过滤数据,只输出符合条件的文档
db.test.aggregate( {
$match :
{ weight :
{ $gte : 0.5, $lte : 1 }
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
MongoDB语法            MySql语法

db.test.find({'name':'foobar'})<==>
select * from test where name='foobar'

db.test.find()<==>select *from test

db.test.find({'ID':10}).count() <==>
select count(*) from test where ID=10//查询到的数据条数
db.collection.find({条件}).count()或db.collection.count({条件})

db.test.find().skip(10).limit(20)<==>
select * from test limit 10,20//截取10之后的20条数据 .skip(10)指跳过10条数据

db.test.find({'ID':{$in:[25,35,45]}})<==>
select * from test where ID in (25,35,45)//in查询

db.test.find().sort({'ID':-1})<==>
select * from test order by ID desc//降序排列 sort()参数1和-1

db.test.distinct('name',{'ID':{$lt:20}}) <==>
select distinct(name) from test where ID<20//去重
db.collection.distinct(去重字段名,{条件})

(这种分组方式可能已经废弃,版本4.4.2,老版本不超过3)
db.test.group({key:{'name':true},cond:{'name':'foo'},reduce:function(obj,prev){prev.msum+=obj.marks;},initial:{msum:0}})<==>
select name,sum(marks) from test group by name//分组
db.collection.group({key,reduce,initial[,keyf][,cond][,finalize]})
1.key:用来分组文档的字段。和keyf两者必须有一个
2.keyf:可以接受一个javascript函数。用来动态的确定分组文档的字段。和key两者必须有一 个,可选,作用和key相同,但是又不同,keyf可以对数据中的某个或多个字段进行操作以后再分组
3.initial:reduce中使用变量的初始化
4.reduce:函数需要返回值,对返回的值进行操作,执行的reduce函数。obj-原来的数据,prev处理后的数据,group有一个弊端,就是需要返回的值,必须每一个都要操作
5.cond:执行过滤的条件。
6.finallize:在reduce执行完成,结果集返回之前,可以对已经得到的数据进行进一步处理,对结果集最终执行的函数。可选的。


db.test.find('this.ID<20',{name:1})<==>
select name from test whereID<20//范围查询

db.test.insert({'name':'foobar','age':25})<==>
insert into test ('name','age') values('foobar',25)//插入数据

db.test.remove({})<==>delete * from test//删除数据

db.test.remove({'age':20})<==>delete test where age=20//删除符合条件的数据

db.test.remove({'age':{$lt:20}})<==>delete test where age<20//小于

db.test.remove({'age':{$lte:20}})<==>delete test where age<=20//小于等于

db.test.remove({'age':{$gt:20}})<==>delete test where age>20//大于

db.test.remove({'age':{$gte:20}})<==>delete test where age>=20//大于等于

db.test.remove({'age':{$ne:20}})<==>delete test where age!=20//不等于

db.test.update({'name':'foobar'},{$set:{'age':36}})<==>
update test set age=36 where name='foobar'//更新

db.test.update({'name':'foobar'},{$inc:{'age':3}})<==>
update test set age=age+3 where name='foobar'//更新-字段+3

模糊查询:$regex
db.test.find({"name":{$regex:"aaa"}})

分组个数过滤
db.getCollection('id_mapper').aggregate([{$group:{ _id :"$contract_id",count:{$sum:1}}},{$match:{count:{$gt:1}}}])

判断是否为空——就是找字段为空的字段数据
db.getCollection('id_mapper').find({"sinocardid":{$in:[null]}})
或db.id_mapper.find({"sinocardid":{$in:[null]}})
group的使用
1
2
3
4
5
6
7
8
9
10
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }
参数说明:
_id :强制必须存在(这里为分组字段)
<field1>:随意命名,用于显示的字段,后面跟上 函数:要统计字段
$sum:和
$avg:平均数
$max:最大值
$min:最小值
$first:第一条数据内容
$last:最后一条数据内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 插入数据
db.getCollection('sales').insertMany([
{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-03-01T08:00:00Z") },
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-03-01T09:00:00Z") },
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-03-15T09:00:00Z") },
{ "_id" : 4, "item" : "xyz", "price" : 5, "quantity" : 20, "date" : ISODate("2014-04-04T11:21:39.736Z") },
{ "_id" : 5, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-04-04T21:23:13.331Z") }
]);
————————————————
按照 item 字段进行分组,统计每个 item 下面的文档个数

db.sales.aggregate([
{
$group : {
_id : "$item",
count: { $sum : 1}
}
}
]);

// 返回结果
{ "_id" : "xyz", "count" : 2 }
{ "_id" : "jkl", "count" : 1 }
{ "_id" : "abc", "count" : 2 }
————————————————
按照 item 字段进行分组,统计每个 item 下面 price 的总数,quantity 的平均数
db.sales.aggregate([
{
$group : {
_id : "$item",
totalPrice: { $sum : "$price"},
avgQuantity: { $avg: "$quantity" }
}
}
]);

// 返回结果
{ "_id" : "xyz", "totalPrice" : 10, "avgQuantity" : 15 }
{ "_id" : "jkl", "totalPrice" : 20, "avgQuantity" : 1 }
{ "_id" : "abc", "totalPrice" : 20, "avgQuantity" : 6 }
————————————————
db.sales.aggregate([
{
$group : {
// _id : { filed : value } 这个结构是自定义,用来定义按照什么分组
// "$date" 表示操作这个字段, $month、$dayOfMonth 和 $year 是表示从 $date 里面取出对应日期数据
_id : { month: { $month: "$date" }, day: { $dayOfMonth: "$date" }, year: { $year: "$date" } },

// [ "$price", "$quantity" ] 指的是操作这两个数据,$multiply 对多个字段进行求积操作
totalPrice: { $sum: { $multiply: [ "$price", "$quantity" ] } },

// "$quantity" 值的是操作这个数据,$avg 来求平均数
averageQuantity: { $avg: "$quantity" },
// 统计有几条集合数据
count: { $sum: 1 }
}
}
]);

// 返回结果:
{ "_id" : { "month" : 4, "day" : 4, "year" : 2014 }, "totalPrice" : 200, "averageQuantity" : 15, "count" : 2 }
{ "_id" : { "month" : 3, "day" : 15, "year" : 2014 }, "totalPrice" : 50, "averageQuantity" : 10, "count" : 1 }
{ "_id" : { "month" : 3, "day" : 1, "year" : 2014 }, "totalPrice" : 40, "averageQuantity" : 1.5, "count" : 2 }
————————————————

另一种操作方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 数据如下
db.getCollection('sales1').insertMany([
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 },
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }])
————————————————
使用 $push 操作,将数据拼接到一个数组中
// 按照 author 分组,将同一个 author 的title 拼接到一个数组中
db.books.aggregate(
[
{ $group : { _id : "$author", books: { $push: "$title" } } }
]
);

// 返回结果
{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] }
{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }
————————————————
在上面的操作中存在一个问题,如果是存在重复的数据,重复的数据也会一起放入到返回的结果中,对于这样子的情况使用以下操作(去重):

// 使用 $addToSet 操作
db.books.aggregate(
[
{ $group : { _id : "$author", books: { $addToSet: "$title" } } }
]
);
使用 $$ROOT (系统变量-即原字段)操作,返回生成的文档不得超过BSON文档大小限制。
————————————————
// 查询操作
db.books.aggregate(
[
{ $group : { _id : "$author", books: { $push: "$$ROOT" } } }
]
)

// 返回结果
{
"_id" : "Homer",
"books" :
[
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
]
}

{
"_id" : "Dante",
"books" :
[
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }
]
}
————————————————
分组数据是无序的,并且都是在内存中操作完成,所以操作的时候,不能支持大数据量。