MongoDB的基础认识

一、什么是NOSQL

NoSQL概念。

随着web2.0的快速发展,非关系型、分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性。NoSQL概念在2009年被提了出来。NoSQL最常见的解释是“non-relational”,“Not Only SQL”也被很多人接受。

为什么要使用NOSQL非关系数据库。

随着互联网web2.0网站的兴起,非关系型的数据库现在成了一个极其热门的新领域,非关系数据库产品的发展非常迅速。而传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,例如:
1、High performance - 对数据库高并发读写的需求
2、Huge Storage - 对海量数据的高效率存储和访问的需求
3、High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求
在上面提到的“三高”需求面前,关系数据库遇到了难以克服的障碍,而对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地,例如:
1、数据库事务一致性需求
2、数据库的写实时性和读实时性需求
3、对复杂的SQL查询,特别是多表关联查询的需求
因此,关系数据库在这些越来越多的应用场景下显得不那么合适了,为了解决这类问题的非关系数据库应运而生。
NoSQL 是非关系型数据存储的广义定义。它打破了长久以来关系型数据库与ACID理论大一统的局面。NoSQL 数据存储不需要固定的表结构,通常也不存在连接操作。在大数据存取上具备关系型数据库无法比拟的性能优势。该术语在 2009 年初得到了广泛认同。

二、MONGODB的结构与特性

MongoDB特性



MONGODB的优缺点



MongoDB数据架构



Mongodb的数据文件

MongoDB每个数据库都有自己的独立文件,如果开启 directoryperdb 选项,则每个库的文件会单独放在一个文件夹里。每个库由一个名字空间文件和多个数据文件组成,名字空间文件以.ns结尾,数据文件按照数据量大小由0开始增长,第一个数据文件为64M,翻倍增长直至2G。.ns文件保存数据库所有名字空间,每一个集合、索引都将占用一个命名空间以保存元数据。默认16M最大为2G,启动时可通过nssize参数选项更改ns文件大小以增加可创建集合及索引个数。使用预分配数据文件方式来保证写入性能的稳定(可用–noprealloc关闭)。预分配在后台进行,并且每个预分配的文件都用0进行填充。数据库启动后会产生一个6bytes的mongd.lock数据文件,用于防止同一个实例多次运行,非正常退出后需要删除此文件才能重启成功。

MONGODB的内存使用机制

内存管理采用OS的MMAP内存映射机制,把数据文件映射到内存中,读操作可以起到缓存作用,写操作可由内存转化成顺序磁盘写入。操作系统虚拟内存管理器会托管所有磁盘操作,这样MongoDB内存管理实现会很简单,缺点是人工没有办法控制占多大内存。32位主机最大寻址4GB,1GB用于kernel,约0.5GB用于MongoDB Stack空间,剩下约2.5G可用于映射数据文件,超出报”mmap failed with out of memory”。64位主机最大可映射128TB数据

三、项目DB类型选择

Mongodb与mysql比较



项目的db选择理由

1、使用MongoDB:
不需要设计表与表之间的关系
单表数据量大
性能要求高

2、使用Mysql:
单表数据不大(500w以内)
Mysql性能可以满足需求
项目成员对mongodb不熟悉

四、常用操作

Mongodb启动

数据库启动:
mongod --dbpath=/data/db --logpath=/mongodb/mongodb.log --fork --logappend
--dbpath指定数据库文件存放目录,
--logpath指定日志文件存放目录,
--fork指定服务后台执行,
--logappend指定日志写入模式为增加,默认为覆盖
启动客户端连接:
mongo 127.0.0.1:27017/dbname

Mongodb关闭

在admin库中使用db.shutdownServer()
> use admin;
> db.shutdownServer();
使用kill -2或 kill -15,不要使用kill -9 这样可能会导致数据库损坏

创建及删除数据库

1、创建数据库
show dbs; 查看所有数据库
show collections; 查看当前库的集合
use things 若存在things数据库,则切换到things上,若不存在,则建立things数据库
2、删除数据库
db.dropDatabase();删除当前数据库

插入数据

建立对象a和b
a={name:"mongo"};
b={x:3};

保存a和b到集合中
db.things.save(a);
db.things.save(b);
 
或者使用db.things.insert(a);
也可以直接db.things.insert({name:”mongo”});

认识find



普通查询

db.things.find();
db.things.find().forEach(printjson);

使用游标:
var cur=db.things.find();取得游标
while (cur.hasNext()) printjson(cur.next());显示所有结果
查询的时候加上pretty()就可以对结果格式化

条件查询

db.things.find({name:”mongo”});相当于select * from things where name=”mongo”;
db.things.find({x:4,j:1}); 相当于select * from things where x=4,j=1;
db.things.find({x:4},{j:true});相当于select j from things where x=4;
或者使用db.things.find(null,{j:1});,若不想显示_id,可用db.things.find(null,{j:1,_id:0});

db.things.find({x:{$ne:3},j:{$gte:1}});
$lt,$lte,$gt,$gte,$ne分别为<,<=,>,>=,!=

db.things.find({j:{$exists:false}});
$exists是否存在,即查找不存在j的数据

db.things.find({x:4,$or:[{j:1},{j:2},{j:3}]};
$or和$and,即x=4 and (j=1 or j=2 or j=3)

限制查询结果数量

db.things.findOne({x:4}); 只显示一条查询结果
db.things.find().limit(3); 显示三条查询结果
db.things.find().limit(2).skip(1);显示第二个和第三个结果,skip规定忽略几个

查询条件操作符



排序与聚合

结果排序
db.things.find().sort({j:1}); 按j的升序排序
db.things.find().sort({x:1,j:-1}); 按x的升序,j的降序排序

聚合结果
db.things.count();
db.things.find().count();
db.things.count({j:{$gt:10}});
db.things.distinct(“name”);

聚合操作--group

group是较为复杂的聚合操作,它与关系型数据库中的GROUP BY类似,但更加强大。

group先选定分组依据的键,然后将集合根据键值的不同分成若干组。之后再聚合每一组内的文档产生查询结果。

参数说明:
key:分组依据;
cond:查询条件;
reduce:聚合操作;
initial:指定聚合计数器的初始对象;

db.Player.group({'key':{'isBoy':true},'cond':{_id:{$gt:0}},'reduce':function(obj,prev){prev.sum+=1;},'initial':{'sum':0}});

sql伪代码
SELECT a, b, SUM(c), CSUM
FROM COLL
WHERE active = 1
GROUP BY a, b


MongoDB
db.coll.group({
  'key': {
    'a': true,
    'b': true
  },
  'cond': { 'active':1 }, 
  'reduce': function(obj, prev)   
  {
    prev.csum += obj.c;
  },
  'initial': { 'csum': 0 }
});


数组查询$size $slice

$size用来匹配数组长度(即最大下标):
// 返回comments包含5个元素的文档
db.posts.find({comments:{‘$size’: 5}});
请注意:$size操作符并不能与其他查询操作符(子句)联合使用,这意味着您不能使用如下代码:
// 以下的使用方法是错误的
db.posts.find({comments:{‘$size’: { ‘$gt’: 5 }}});

$slice操作符类似于子键筛选,只不过它筛选的是数组中的项。
// 仅返回数组中的前5项
db.posts.find({},{comments:{‘$slice’: 5}});

// 仅返回数组中的最后5项
db.posts.find({},{comments:{‘$slice’: -5}});

// 跳过数组中的前20项,返回接下来的10项
db.posts.find({},{comments:{‘$slice’: [20, 10]}});

// 跳过数组中的最后20项,返回接下来的10项
db.posts.find({},{comments:{‘$slice’: [-20, 10]}});

更新

db.things.update({name:”mongo”},{$set:{name:”mongo_new”}});将name为mongo更新为mongo_new

db.things.update({},{name:”mongo_new”}); 将所有数据的name都更新为mongo_new

更新文档实例:
// 原文档
{
"_id" : ObjectId("4b2b9f67a1f631733d917a7a"),
"name" : "joe",
"friends" : 32,
"enemies" : 2
}

// 期望结果
{
"_id" : ObjectId("4b2b9f67a1f631733d917a7a"),
"username" : "joe",
"relationships" :
{
"friends" : 32,
"enemies" : 2
}
}

// 操作:首先查找记录
var joe = db.users.findOne({"name" : "joe"});

// 修改记录属性,很普通的JavaScript语法
joe.relationships = {"friends" : joe.friends, "enemies" : joe.enemies};
joe.username = joe.name;
delete joe.friends;
delete joe.enemies;
delete joe.name;

// 更新
db.users.update({ "name" : "joe" }, joe);

更新文档——upsert模式


// 更新:指定第三个参数为true可以开启upsert模式
db.users.update({ "name" : "joe" }, joe, true);
在upsert模式下,如果找到匹配的记录则更新之,否则如果找不到匹配记录就会创建一条新的记录。

// 更新:指定第四个参数为true可以开启multi模式
db.users.update({ "name" : "joe" }, joe, true, true);
默认情况下update只会更新第一个匹配到的文档,开启multi模式,才会更新所有匹配到的文档。

删除

db.things.remove(); 删除集合中所有文档

db.things.remove({name:”mongo_new”}); 删除指定条件文档

五、常用备份、恢复命令

备份与恢复——冷备份

优点:可以完全保证数据完整性;
缺点:需要数据库引擎离线



数据库备份

./mongoexport –d my_mongodb –c user –o user.dat
./mongoexport –d my_mongodb –c user –csv –f uid,username,age –o user_csv.dat
./mongodump  -d my_mongodb –o /dir

数据库恢复

./mongoimport –d my_mongodb –c user user.dat
./mongoimport –d my_mongodb –c user --type csv –headerline --file user_csv.dat
./mongorestore -d my_mongodb  /dir/my_mongodb

两种备份恢复工具比较

备份方面:mongodump的速度和压缩率都最好mongoexport导出的json,csv可能对某些数据类型不兼容,因此可能不能全部数据导出,mongodump就可以全部兼容。
恢复方面: mongoimport速度较快,但不保证数据完整导入 mongorestore,速度较慢,但是根据mongodump导出的数据,可以完整导入数据。

猜你喜欢

转载自fun-virus.iteye.com/blog/1922683