mongo

来源:互联网 发布:奇门遁甲排盘软件 编辑:程序博客网 时间:2024/05/05 11:09

概念 (非关系型文档)

区别 (mysql cache  json)

使用 (curd  聚合)

高可用 (主从 分片)

场景 (关联低 效率高)

高级 (mapreduce  gridfs)

其他 (地图 。。)

1.MySQL与MongoDB都是开源的常用数据库,mongodb以BSON结构(二进制)进行存储,对海量数据存储有着很明显的优势。下面是Mongodb与Mysql的操作命令的对比。

2.区别

BSON是由10gen开发的一个数据格式,目前主要用于MongoDB中,是MongoDB的数据存储格式。BSON基于JSON格式,选择JSON进行改造的原因主要是JSON的通用性及JSON的schemaless的特性。

BSON主要会实现以下三点目标:

1.更快的遍历速度

对JSON格式来说,太大的JSON结构会导致数据遍历非常慢。在JSON中,要跳过一个文档进行数据读取,需要对此文档进行扫描才行,需要进行麻烦的数据结构匹配,比如括号的匹配,而BSON对JSON的一大改进就是,它会将JSON的每一个元素的长度存在元素的头部,这样你只需要读取到元素长度就能直接seek到指定的点上进行读取了。

2.操作更简易

对JSON来说,数据存储是无类型的,比如你要修改基本一个值,从9到10,由于从一个字符变成了两个,所以可能其后面的所有内容都需要往后移一位才可以。而使用BSON,你可以指定这个列为数字列,那么无论数字从9长到10还是100,我们都只是在存储数字的那一位上进行修改,不会导致数据总长变大。当然,在MongoDB中,如果数字从整形增大到长整型,还是会导致数据总长变大的。

3.增加了额外的数据类型

JSON是一个很方便的数据交换格式,但是其类型比较有限。BSON在其基础上增加了“byte array”数据类型。这使得二进制的存储不再需要先base64转换后再存成JSON。大大减少了计算开销和数据大小。

当然,在有的时候,BSON相对JSON来说也并没有空间上的优势,比如对{“field”:7},在JSON的存储上7只使用了一个字节,而如果用BSON,那就是至少4个字节(32位)

目前在10gen的努力下,BSON已经有了针对多种语言的编码解码包。并且都是Apache 2 license下开源的。并且还在随着MongoDB进一步地发展。关于BSON,



作用

MySQL

MongoDB

 

 

 

服务器守护进程

mysqld

mongod

客户端工具

mysql

mongo

逻辑备份工具

mysqldump

mongodump

逻辑还原工具

mysql

mongorestore

数据导出工具

mysqldump

mongoexport

数据导入工具

source

mongoimport

 

 



3.指令

一、数据库常用命令
1、Help查看命令提示


help
db.help();
db.yourColl.help();
db.youColl.find().help();
rs.help();


2、切换/创建数据库


use yourDB; 当创建一个集合(table)的时候会自动创建当前数据库


3、查询所有数据库


show dbs;


4、删除当前使用数据库


db.dropDatabase();


5、从指定主机上克隆数据库


db.cloneDatabase("127.0.0.1"); 将指定机器上的数据库的数据克隆到当前数据库


6、从指定的机器上复制指定数据库数据到某个数据库


db.copyDatabase("mydb", "temp", "127.0.0.1");将本机的mydb的数据复制到temp数据库中


7、修复当前数据库


db.repairDatabase();


8、查看当前使用的数据库


db.getName();
db; db和getName方法是一样的效果,都可以查询当前使用的数据库


9、显示当前db状态


db.stats();


10、当前db版本


db.version();


11、查看当前db的链接机器地址


db.getMongo();


二、Collection聚集集合
1、创建一个聚集集合(table)


db.createCollection("collName", {size: 20, capped: 5, max: 100});//创建成功会显示{"ok":1}
//判断集合是否为定容量db.collName.isCapped();


2、得到指定名称的聚集集合(table)


db.getCollection("account");


3、得到当前db的所有聚集集合


db.getCollectionNames();


4、显示当前db所有聚集索引的状态


db.printCollectionStats();


三、用户相关
1、添加一个用户


db.createUser(
{
user: "root",
pwd: "root",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
2、数据库认证、安全模式


db.auth("userName", "123123");


3、显示当前所有用户


show users;


4、删除用户


db.removeUser("userName");


四、聚集集合查询
1、查询所有记录


db.users.find();
相当于:select* from users;


默认每页显示20条记录,当显示不下的情况下,可以用it迭代命令查询下一页数据。注意:键入it命令不能带";"
但是你可以设置每页显示数据的大小,用DBQuery.shellBatchSize= 50;这样每页就显示50条记录了。
2、查询去掉后的当前聚集集合中的某列的重复数据


db.users.distinct("name");
会过滤掉name中的相同数据
相当于:select distict name from users;


3、查询age = 22的记录


db.users.find({"age": 22});
相当于: select * from users where age = 22;


4、查询age > 22的记录


db.users.find({age: {$gt: 22}});
相当于:select * from users where age >22;


5、查询age < 22的记录


db.users.find({age: {$lt: 22}});
相当于:select * from users where age <22;


6、查询age >= 25的记录


db.users.find({age: {$gte: 25}});
相当于:select * from users where age >= 25;


7、查询age <= 25的记录


db.users.find({age: {$lte: 25}});


8、查询age >= 23 并且 age <= 26


db.users.find({age: {$gte: 23, $lte: 26}});


9、查询name中包含 mongo的数据


db.users.find({name: /mongo/});
//相当于%%
[code]select * from users where name like ‘%mongo%';


10、查询name中以mongo开头的


db.users.find({name: /^mongo/});
select * from users where name like ‘mongo%';


11、查询指定列name、age数据


db.users.find({}, {name: 1, age: 1});
相当于:select name, age from users;


当然name也可以用true或false,当用ture的情况下河name:1效果一样,如果用false就是排除name,显示name以外的列信息。
12、查询指定列name、age数据, age > 25


db.users.find({age: {$gt: 25}}, {name: 1, age: 1});
相当于:select name, age from users where age >25;


13、按照年龄排序


升序:db.users.find().sort({age: 1});
降序:db.users.find().sort({age: -1});


14、查询name = zhangsan, age = 22的数据


db.users.find({name: 'zhangsan', age: 22});
相当于:select * from users where name = ‘zhangsan' and age = ‘22';


15、查询前5条数据


db.users.find().limit(5);
相当于:selecttop 5 * from users;


16、查询10条以后的数据


db.users.find().skip(10);
相当于:select * from users where id not in (
selecttop 10 * from users
);


17、查询在5-10之间的数据


db.users.find().limit(10).skip(5);


可用于分页,limit是pageSize,skip是第几页*pageSize
18、or与 查询


db.users.find({$or: [{age: 22}, {age: 25}]});
相当于:select * from users where age = 22 or age = 25;


19、查询第一条数据


db.users.findOne();
相当于:selecttop 1 * from users;
db.users.find().limit(1);


20、查询某个结果集的记录条数


db.users.find({age: {$gte: 25}}).count();
相当于:select count(*) from users where age >= 20;


21、按照某列进行排序


db.users.find({sex: {$exists: true}}).count();
相当于:select count(sex) from users;


五、索引
1、创建索引


db.users.ensureIndex({name: 1});
db.users.ensureIndex({name: 1, ts: -1});


2、查询当前聚集集合所有索引


db.users.getIndexes();


3、查看总索引记录大小


db.users.totalIndexSize();


4、读取当前集合的所有index信息


db.users.reIndex();


5、删除指定索引


db.users.dropIndex("name_1");


6、删除所有索引索引


db.users.dropIndexes();


六、修改、添加、删除集合数据
1、添加


db.users.save({name: ‘zhangsan', age: 25, sex: true});


添加的数据的数据列,没有固定,根据添加的数据为准
2、修改


db.users.update({age: 25}, {$set: {name: 'changeName'}}, false, true);
相当于:update users set name = ‘changeName' where age = 25;
db.users.update({name: 'Lisi'}, {$inc: {age: 50}}, false, true);
相当于:update users set age = age + 50 where name = ‘Lisi';
db.users.update({name: 'Lisi'}, {$inc: {age: 50}, $set: {name: 'hoho'}}, false, true);
相当于:update users set age = age + 50, name = ‘hoho' where name = ‘Lisi';


3、删除


db.users.remove({age: 132});


4、查询修改删除


db.users.findAndModify({
query: {age: {$gte: 25}},
sort: {age: -1},
update: {$set: {name: 'a2'}, $inc: {age: 2}},
remove: true
});
db.runCommand({ findandmodify : "users",
query: {age: {$gte: 25}},
sort: {age: -1},
update: {$set: {name: 'a2'}, $inc: {age: 2}},
remove: true
});


update 或 remove 其中一个是必须的参数; 其他参数可选。
参数 详解 默认值
query 查询过滤条件 {}
sort 如果多个文档符合查询过滤条件,将以该参数指定的排列方式选择出排在首位的对象,该对象将被操作 {}
remove 若为true,被选中对象将在返回前被删除 N/A
update 一个 修改器对象
N/A
new 若为true,将返回修改后的对象而不是原始对象。在删除操作中,该参数被忽略。 false
fields 参见Retrieving a Subset of Fields (1.5.0+)
All fields
upsert 创建新对象若查询结果为空。 示例 (1.5.4+)
false
七、语句块操作
1、简单Hello World


print("Hello World!");


这种写法调用了print函数,和直接写入"Hello World!"的效果是一样的;
2、将一个对象转换成json


tojson(new Object());
tojson(new Object('a'));


3、循环添加数据


> for (var i = 0; i < 30; i++) {
... db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});
... };


这样就循环添加了30条数据,同样也可以省略括号的写法


> for (var i = 0; i < 30; i++) db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});


也是可以的,当你用db.users.find()查询的时候,显示多条数据而无法一页显示的情况下,可以用it查看下一页的信息;
4、find 游标查询


>var cursor = db.users.find();
> while (cursor.hasNext()) {
printjson(cursor.next());
}


这样就查询所有的users信息,同样可以这样写


var cursor = db.users.find();
while (cursor.hasNext()) { printjson(cursor.next); }


同样可以省略{}号
5、forEach迭代循环


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


forEach中必须传递一个函数来处理每条迭代的数据信息
6、将find游标当数组处理


var cursor = db.users.find();
cursor[4];


取得下标索引为4的那条数据
既然可以当做数组处理,那么就可以获得它的长度:cursor.length();或者cursor.count();
那样我们也可以用循环显示数据


for (var i = 0, len = c.length(); i < len; i++) printjson(c[i]);


7、将find游标转换成数组


> var arr = db.users.find().toArray();
> printjson(arr[2]);


用toArray方法将其转换为数组
8、定制我们自己的查询结果
只显示age <= 28的并且只显示age这列数据


db.users.find({age: {$lte: 28}}, {age: 1}).forEach(printjson);
db.users.find({age: {$lte: 28}}, {age: true}).forEach(printjson);


排除age的列


db.users.find({age: {$lte: 28}}, {age: false}).forEach(printjson);


9、forEach传递函数显示信息


db.things.find({x:4}).forEach(function(x) {print(tojson(x));});


八、其他
1、查询之前的错误信息


db.getPrevError();


2、清除错误记录


db.resetError();


查看聚集集合基本信息
1、查看帮助 db.yourColl.help();
2、查询当前集合的数据条数 db.yourColl.count();
3、查看数据空间大小 db.users.dataSize();
4、得到当前聚集集合所在的db db.users.getDB();
5、得到当前聚集的状态 db.users.stats();
6、得到聚集集合总大小 db.users.totalSize();
7、聚集集合储存空间大小 db.users.storageSize();
8、Shard版本信息 db.users.getShardVersion()
9、聚集集合重命名 db.users.renameCollection("users"); 将users重命名为users
10、删除当前聚集集合 db.users.drop();



show dbs:显示数据库列表
show collections:显示当前数据库中的集合(类似关系数据库中的表)
show users:显示用户
use <db name>:切换当前数据库,这和MS-SQL里面的意思一样
db.help():显示数据库操作命令,里面有很多的命令
db.foo.help():显示集合操作命令,同样有很多的命令,foo指的是当前数据库下,一个叫foo的集合,并非真正意义上的命令
db.foo.find():对于当前数据库中的foo集合进行数据查找(由于没有条件,会列出所有数据)
db.foo.find( { a : 1 } ):对于当前数据库中的foo集合进行查找,条件是数据中有一个属性叫a,且a的值为1





1、操作数据库


如果没有指定要连接的数据库名,mongo shell会默认连接test数据库。


我们可以使用use <database>来切换数据库,这个数据库不必事先创建:

[javascript] view plaincopy
> use mydb switched to db mydb 


显示目前使用的数据库名:

[javascript] view plaincopy
> db mydb 


往集合docs里查询一条数据:

[javascript] view plaincopy
> db.docs.insert({x:1,y:1}) 


查询集合docs里的文档:

[javascript] view plaincopy
> db.docs.find() { "_id" : ObjectId("51de4d33b41543f9704cc936"), "x" : 1, "y" : 1 } 

我们可以看到这个文档比我们添加的数据多了一项_id,其类型是ObjectId。所有的MongoDB文档都需要有_id,且它的值必须是唯一的。如果我们插入的文档中没有这一项,MongoDB在插入数据库前会自动为这个文档生成一个新的ObjectId。


使用$set来更新一个文档:

[javascript] view plaincopy
> db.docs.update({x:1},{$set:{y:2}}) > db.docs.find() { "_id" : ObjectId("51de4d33b41543f9704cc936"), "x" : 1, "y" : 2 } 

这里用到了$set操作,否则MongoDB的Update命令只会保留_id和需要更新的域。


不使用$set来更新文档:

[javascript] view plaincopy
> db.docs.update({x:1},{y:3}) > db.docs.find() { "_id" : ObjectId("51de4d33b41543f9704cc936"), "y" : 3 } 

从这个例子我们可以看到由于我们没有使用$set,更新后的文档里{x:1}被删除了。


删除一个文档:

[javascript] view plaincopy
> db.docs.remove({y:3}) > db.docs.find() > 

2、聚合操作


这里我们介绍一下聚合框架中常用的几个操作:


$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group:将集合中的文档分组,可用于统计结果。
$sort:将输入文档排序后输出。
$geoNear:输出接近某一地理位置的有序文档。


更多的介绍可以参考:http://docs.mongodb.org/manual/reference/aggregation/



实例


在下面的这个例子里我们将学习如何使用MongoDB的聚合框架来处理分析数据。


首先,在Mongo Shell里运行下面的脚本在test数据库里创建一个叫articles的集合。



[javascript] view plaincopy
use test; 
allAuthors = ["Bob", "Tom", "Lucy", "Steve", "Kate", "Lily"]; 
allTags = ["MongoDB", "Database", "Linux", "Windows", "Solaris", "Mac"]; 

for(var i=0; i<1000; i )
{ _id = i; 
title = "title" i; 
author = allAuthors[Math.floor(Math.random()*allAuthors.length)]; 
posted = new Date (2012,Math.floor(Math.random()*12), Math.floor(Math.random()*28)); 
pageViews = Math.floor(Math.random()*10001); 
tags = allTags[Math.floor(Math.random()*allTags.length)]; 
db.articles.save({"_id":_id, "title":title, "author":author, "posted":posted, "pageViews":pageViews, "tags":[tags]}); 
db.articles.update({"_id": _id}, {$addToSet:{tags: {$each : [ allTags[Math.floor(Math.random()*allTags.length)], allTags[Math.floor(Math.random()*allTags.length)] ]}}}); 
} ;



这个集合存放了精简的博客的信息,包括作者、标题、查看的次数、发布时间、标签。生成的集合的文档样本如下:

[javascript] view plaincopy
{ "_id" : 0, "author" : "Steve", "pageViews" : 2606, "posted" : ISODate("2012-07-31T14:00:00Z"), "tags" : [ "MongoDB", "Mac", "Database" ], "title" : "title0" }



好了,有了这些数据,我们可以开始学习使用聚合操作了。假设我们要从2012年7月1号以及以后发布的博客里查找第二和第三热门的标签。聚合操作可以拆分成下面几步:


1、查找2012年7月1号及以后发布的博客:

[javascript] view plaincopy
{ $match : { posted : { $gte : new Date(2012-7-1) } } }, 

2、拆分tags数组:

[javascript] view plaincopy
{ $unwind : "$tags" }, 

3、将拆分的文档按tags域来分组,并统计各个标签出现的次数。$group中的_id域是分组的标准。

[javascript] view plaincopy
{ $group : { _id : "$tags", total : { $sum : 1 } } }, 

4、将统计结果排序:

[javascript] view plaincopy
{ $sort : { _id : -1 } }, 

5、跳过第一条纪录:

[javascript] view plaincopy
{ $skip : 1 }, 

6、只输出两条结果:

[javascript] view plaincopy
{ $limit : 2 }, 

7、将输出结果重新命名。

[javascript] view plaincopy
{ $project : { tags : "$_id", total : 1, _id : 0 } } 


聚合操作命令如下:

[javascript] view plaincopy
db.articles.aggregate([ { $match : { posted : { $gte : new Date(2012-7-1) } } }, { $unwind : "$tags" }, { $group : { _id : "$tags", total : { $sum : 1 } } }, { $sort : { _id : -1 } }, { $skip : 1 }, { $limit : 2 }, { $project : { tags : "$_id", total : 1, _id : 0 } } ])


得到的结果为:

[javascript] view plaincopy
{ "result" : [ { "total" : 428, "tags" : "Solaris" }, { "total" : 420, "tags" : "MongoDB" } ], "ok" : 1 }


需要注意的是聚合操作返回的结果是一个文档,所以受到BSON文档大小的限制,目前的限制为16兆。






/**
* 4.PHP操作MongoDB学习笔记
*/




//simplify
/*
 * MongoDB PHP


在php中使用mongodb你必须使用 mongodb的php驱动。


MongoDB PHP在各平台上的安装及驱动包下载请查看:PHP安装MongoDB扩展驱动
确保连接及选择一个数据库


为了确保正确连接,你需要指定数据库名,如果数据库在mongoDB中不存在,mongoDB会自动创建


代码片段如下:


<?php
   // 连接到mongodb
   $m = new MongoClient();
   echo "Connection to database successfully";
   // 选择一个数据库
   $db = $m->mydb;
   echo "Database mydb selected";
?>


执行以上程序,输出结果如下:


Connection to database successfully
Database mydb selected


创建集合


创建集合的代码片段如下:


<?php
   // 连接到mongodb
   $m = new MongoClient();
   echo "Connection to database successfully";
   // 选择一个数据库
   $db = $m->mydb;
   echo "Database mydb selected";
   $collection = $db->createCollection("mycol");
   echo "Collection created succsessfully";
?>


执行以上程序,输出结果如下:


Connection to database successfully
Database mydb selected
Collection created succsessfully


插入文档


在mongoDB中使用 insert() 方法插入文档:


插入文档代码片段如下:


<?php
   // 连接到mongodb
   $m = new MongoClient();
   echo "Connection to database successfully";
   // 选择一个数据库
   $db = $m->mydb;
   echo "Database mydb selected";
   $collection = $db->mycol;
   echo "Collection selected succsessfully";
   $document = array( 
      "title" => "MongoDB", 
      "description" => "database", 
      "likes" => 100,
      "url" => "http://www.w3cschool.cc/mongodb/",
      "by", "w3cschool.cc"
   );
   $collection->insert($document);
   echo "Document inserted successfully";
?>


执行以上程序,输出结果如下:


Connection to database successfully
Database mydb selected
Collection selected succsessfully
Document inserted successfully


查找文档


使用find() 方法来读取集合中的文档。


读取使用文档的代码片段如下:


<?php
   // 连接到mongodb
   $m = new MongoClient();
   echo "Connection to database successfully";
   // 选择一个数据库
   $db = $m->mydb;
   echo "Database mydb selected";
   $collection = $db->mycol;
   echo "Collection selected succsessfully";


   $cursor = $collection->find();
   // 迭代显示文档标题
   foreach ($cursor as $document) {
      echo $document["title"] . "\n";
   }
?>


执行以上程序,输出结果如下:


Connection to database successfully
Database mydb selected
Collection selected succsessfully
{
   "title": "MongoDB"
}


更新文档


使用 update() 方法来更新文档。


以下实例将更新文档中的标题为' MongoDB Tutorial', 代码片段如下:


<pre>
<?php
   // 连接到mongodb
   $m = new MongoClient();
   echo "Connection to database successfully";
   // 选择一个数据库
   $db = $m->mydb;
   echo "Database mydb selected";
   $collection = $db->mycol;
   echo "Collection selected succsessfully";


   // 更新文档
   $collection->update(array("title"=>"MongoDB"), array('$set'=>array("title"=>"MongoDB Tutorial")));
   echo "Document updated successfully";
   // 显示更新后的文档
   $cursor = $collection->find();
   // 循环显示文档标题
   echo "Updated document";
   foreach ($cursor as $document) {
      echo $document["title"] . "\n";
   }
?>


执行以上程序,输出结果如下:


Connection to database successfully
Database mydb selected
Collection selected succsessfully
Document updated successfully
Updated document
{
   "title": "MongoDB Tutorial"
}


删除文档


使用 remove() 方法来删除文档。


以下实例中我们将移除 'title' 为 'MongoDB Tutorial' 的数据记录。, 代码片段如下:


<?php
   // 连接到mongodb
   $m = new MongoClient();
   echo "Connection to database successfully";
   // 选择一个数据库
   $db = $m->mydb;
   echo "Database mydb selected";
   $collection = $db->mycol;
   echo "Collection selected succsessfully";
   
   // 移除文档
   $collection->remove(array("title"=>"MongoDB Tutorial"),false);
   echo "Documents deleted successfully";
   
   // 显示可用文档数据
   $cursor = $collection->find();
   // iterate cursor to display title of documents
   echo "Updated document";
   foreach ($cursor as $document) {
      echo $document["title"] . "\n";
   }
?>


执行以上程序,输出结果如下:


Connection to database successfully
Database mydb selected
Collection selected succsessfully
Documents deleted successfully
 * 
 * 
 */


//more
//*************************
//**   连接MongoDB数据库  **//
//*************************
//格式=>("mongodb://用户名:密码 @地址:端口/默认指定数据库",参数)
$conn = new MongoClient();
//可以简写为
//$conn=new Mongo(); #连接本地主机,默认端口.
//$conn=new Mongo("172.21.15.69"); #连接远程主机
//$conn=new Mongo("xiaocai.loc:10086"); #连接指定端口远程主机
//$conn=new Mongo("xiaocai.loc",array("replicaSet"=>true)); #负载均衡
//$conn=new Mongo("xiaocai.loc",array("persist"=>"t")); #持久连接
//$conn=new Mongo("mongodb://sa:123@localhost"); #带用户名密码
//$conn=new Mongo("mongodb://localhost:27017,localhost:27018"); #连接多个服务器
//$conn=new Mongo("mongodb:///tmp/mongo-27017.sock"); #域套接字
//$conn=new Mongo("mongodb://admin_miss:miss@localhost:27017/test",array('persist'=>'p',"replicaSet"=>true)); #完整
//详细资料:http://www.php.net/manual/en/mongo.connecting.php
//*************************
//**   选择数据库与表    **//
//*************************
$db=$conn->mydb; #选择mydb数据库
//$db=$conn->selectDB("mydb"); #第二种写法
$collection=$db->column; #选择集合(选择'表')
//$collection=$db->selectCollection('column'); #第二种写法
//$collection=$conn->mydb->column; #更简洁的写法
//注意:1.数据库和集合不需要事先创建,若它们不存在则会自动创建它们.
//   2.注意错别字,你可能会无意间的创建一个新的数据库(与原先的数据库混乱).
//*************************
//**   插入文档     **//
//*************************
//**向集合中插入数据,返回bool判断是否插入成功. **/
$array=array('column_name'=>'col'.rand(100,999),'column_exp'=>'xiaocai');
$result=$collection->insert($array); #简单插入
var_dump($array);
echo "新记录ID:".$array['_id']; #MongoDB会返回一个记录标识
var_dump($result); #返回:bool(true)
//**向集合中安全插入数据,返回插入状态(数组). **/
$array=array('column_name'=>'col'.rand(100,999),'column_exp'=>'xiaocai2');
$result=$collection->insert($array); #用于等待MongoDB完成操作,以便确定是否成功.(当有大量记录插入时使用该参数会比较有用)
echo "新记录ID:".$array['_id']; #MongoDB会返回一个记录标识
var_dump($array);
#返回:array(3) { ["err"]=> NULL ["n"]=> int(0) ["ok"]=> float(1) }


/*
* *
* 完整格式:insert ( array $a [, array $options = array() ] )
*    insert(array(),array('safe'=>false,'fsync'=>false,'timeout'=>10000))
*       参数:safe:默认false,是否安全写入
*   fsync:默认false,是否强制插入到同步到磁盘
*     timeout:超时时间(毫秒)
*
* 插入结果:{ "_id" : ObjectId("4d63552ad549a02c01000009"), "column_name" : "col770", "column_exp" : "xiaocai" }
*    '_id'为主键字段,在插入是MongoDB自动添加.
*
*    注意:1.以下两次插入的为同一条记录(相同的_id),因为它们的值相同。
*         $collection->insert(array('column_name'=>'xiaocai'));
*         $collection->insert(array('column_name'=>'xiaocai'));
*     避免
* $collection->insert(array('column_name'=>'xiaocai'),true);
* try {
*      $collection->insert(array('column_name'=>'xiaocai'),true);
* }catch(MongoCursorException $e){
*      echo "Can't save the same person twice!\n";
* }
*
*    详细资料:http://www.php.net/manual/zh/mongocollection.insert.php
* *
*/
//*************************
//**   更新文档     **//
//*************************
//** 修改更新 **/
$where=array('column_name'=>'col123');
$newdata=array('column_exp'=>'GGGGGGG','column_fid'=>444);
$result=$collection->update($where,array('$set'=>$newdata)); #$set:让某节点等于给定值,类似的还有$pull $pullAll $pop $inc,在后面慢慢说明用法
/*
* 结果:
* 原数据
* {"_id":ObjectId("4d635ba2d549a02801000003"),"column_name":"col123","column_exp":"xiaocai"}
* 被替换成了
* {"_id":ObjectId("4d635ba2d549a02801000003"),"column_name":"col123","column_exp":"GGGGGGG","column_fid":444}
*/
//** 替换更新 **/
$where=array('column_name'=>'col709');
$newdata=array('column_exp'=>'HHHHHHHHH','column_fid'=>123);
$result=$collection->update($where,$newdata);
/*
* 结果:
* 原数据
* {"_id":ObjectId("4d635ba2d549a02801000003"),"column_name":"col709","column_exp":"xiaocai"}
* 被替换成了
* {"_id":ObjectId("4d635ba2d549a02801000003"),"column_exp":"HHHHHHHHH","column_fid":123}
*/
//** 批量更新 **/
$where=array('column_name'=>'col');
$newdata=array('column_exp'=>'multiple','91u'=>684435);
$result=$collection->update($where,array('$set'=>$newdata),array('multiple'=>true));
/**
* 所有'column_name'='col'都被修改
*/
//** 自动累加 **/
$where=array('91u'=>684435);
$newdata=array('column_exp'=>'edit');
$result=$collection->update($where,array('$set'=>$newdata,'$inc'=>array('91u'=>-5)));
/**
* 更新91u=684435的数据,并且91u自减5
*/
/** 删除节点 **/
//$where=array('column_name'=>'col685');
//$result=$collection->update($where,array('$unset'=>'column_exp'));
/**
* 删除节点column_exp
*/
/*
* *
mongo 版本 1.3以下 
$mongoxbiao->$t_name->update($up,$arr,true);


mongo 版本 1.3及以上 
//$mongoxbiao->$t_name->update($up,$arr,array('upsert'=>true));




* 完整格式:update(array $criteria, array $newobj [, array $options = array()  ] )
*       注意:1.注意区分替换更新与修改更新
*    2.注意区分数据类型如 array('91u'=>'684435')与array('91u'=>684435)
* 详细资料:http://www.mongodb.org/display/DOCS/Updating#Updating-%24bit
* *
*/
//*************************
//**   删除文档     **//
//*************************
/** 清空数据库 **/
$collection->remove(array('column_name'=>'col399'));
//$collection->remove(); #清空集合
/** 删除指定MongoId **/
$id = new MongoId("4d638ea1d549a02801000011");
$collection->remove(array('_id'=>(object)$id));
/*
* *
*  使用下面的方法来匹配{"_id":ObjectId("4d638ea1d549a02801000011")},查询、更新也一样
*  $id = new MongoId("4d638ea1d549a02801000011");
*  array('_id'=>(object)$id)
* *
*/
//*************************
//**   查询文档     **//
//*************************
/** 查询文档中的记录数 **/
echo 'count:'.$collection->count()."<br>"; #全部
echo 'count:'.$collection->count(array('type'=>'user'))."<br>"; #可以加上条件
echo 'count:'.$collection->count(array('age'=>array('$gt'=>50,'$lte'=>74)))."<br>"; #大于50小于等于74
echo 'count:'.$collection->find()->limit(5)->skip(0)->count(true)."<br>"; #获得实际返回的结果数
/**
* 注:$gt为大于、$gte为大于等于、$lt为小于、$lte为小于等于、$ne为不等于、$exists不存在
*/
/** 集合中所有文档 **/
$cursor = $collection->find()->snapshot();
foreach ($cursor as $id => $value) {
echo "$id: "; var_dump($value); echo "<br>";
}
/**
* 注意:
* 在我们做了find()操作,获得$cursor游标之后,这个游标还是动态的.
* 换句话说,在我find()之后,到我的游标循环完成这段时间,如果再有符合条件的记录被插入到collection,那么这些记录也会被$cursor 获得.
* 如果你想在获得$cursor之后的结果集不变化,需要这样做:
* $cursor = $collection->find();
* $cursor->snapshot();
* 详见http://www.bumao.com/index.php/2010/08/mongo_php_cursor.html
*/
/** 查询一条数据 **/
$cursor = $collection->findOne();
/**
*  注意:findOne()获得结果集后不能使用snapshot(),fields()等函数;
*/
/** age,type 列不显示 **/
$cursor = $collection->find()->fields(array("age"=>false,"type"=>false));
/** 只显示user 列 **/
$cursor = $collection->find()->fields(array("user"=>true));
/**
* 我这样写会出错:$cursor->fields(array("age"=>true,"type"=>false));
*/
/** (存在type,age节点) and age!=0 and age<50 **/
$where=array('type'=>array('$exists'=>true),'age'=>array('$ne'=>0,'$lt'=>50,'$exists'=>true));
$cursor = $collection->find($where);
/** 分页获取结果集  **/
$cursor = $collection->find()->limit(5)->skip(0);
/** 排序  **/
$cursor = $collection->find()->sort(array('age'=>-1,'type'=>1)); ##1表示降序 -1表示升序,参数的先后影响排序顺序
/** 索引  **/
$collection->ensureIndex(array('age' => 1,'type'=>-1)); #1表示降序 -1表示升序
$collection->ensureIndex(array('age' => 1,'type'=>-1),array('background'=>true)); #索引的创建放在后台运行(默认是同步运行)
//$collection->ensureIndex(array('age' => 1,'type'=>-1),array('unique'=>true)); #该索引是唯一的
/**
* ensureIndex (array(),array('name'=>'索引名称','background'=true,'unique'=true))
* 详见:http://www.php.net/manual/en/mongocollection.ensureindex.php
*/
/** 取得查询结果 **/
$cursor = $collection->find();
$array=array();
foreach ($cursor as $id => $value) {
$array[]=$value;
}
//*************************
//**   文档聚类     **//
//*************************
//这东西没弄明白…
$conn->close(); #关闭连接
/*
关系型数据库与MongoDB数据存储的区别
MySql数据结构:
CREATE TABLE IF NOT EXISTS `column`(
`column_id` int(16)  NOT NULL  auto_increment  COMMENT '主键',
`column_name` varchar(32) NOT NULL COMMENT '栏目名称',
PRIMARY KEY  (`column_id`)
);
CREATE TABLE IF NOT EXISTS `article`(
`article_id`  int(16)  NOT NULL  auto_increment  COMMENT '主键',
`article_caption` varchar(15) NOT NULL COMMENT '标题',
PRIMARY KEY(`article_id`)
);
CREATE TABLE IF NOT EXISTS `article_body`(
`article_id` int(16) NOT NULL COMMENT 'article.article_id',
`body` text COMMENT '正文'
);
MongoDB数据结构:
$data=array(
'column_name' =>'default',
'article' =>array(
'article_caption' => 'xiaocai',
'body'   => 'xxxxxxxxxx…'
)
);
$inc
如果记录的该节点存在,让该节点的数值加N;如果该节点不存在,让该节点值等于N
设结构记录结构为 array('a'=>1,'b'=>'t'),想让a加5,那么:
$coll->update(
array('b'=>'t'),
array('$inc'=>array('a'=>5)),
)
$set
让某节点等于给定值
设结构记录结构为 array('a'=>1,'b'=>'t'),b为加f,那么:
$coll->update(
array('a'=>1),
array('$set'=>array('b'=>'f')),
)
$unset
删除某节点
设记录结构为 array('a'=>1,'b'=>'t'),想删除b节点,那么:
$coll->update(
array('a'=>1),
array('$unset'=>'b'),
)
$push
如果对应节点是个数组,就附加一个新的值上去;不存在,就创建这个数组,并附加一个值在这个数组上;如果该节点不是数组,返回错误。
设记录结构为array('a'=>array(0=>'haha'),'b'=& gt;1),想附加新数据到节点a,那么:
$coll->update(
array('b'=>1),
array('$push'=>array('a'=>'wow')),
)
这样,该记录就会成为:array('a'=>array(0=>'haha',1=>'wow'),'b'=>1)
$pushAll
与$push类似,只是会一次附加多个数值到某节点
$addToSet
如果该阶段的数组中没有某值,就添加之
设记录结构为array('a'=>array(0=& gt;'haha'),'b'=>1),如果想附加新的数据到该节点a,那么:
$coll->update(
array('b'=>1),
array('$addToSet'=>array('a'=>'wow')),
)
如果在a节点中已经有了wow,那么就不会再添加新的,如果没有,就会为该节点添加新的item——wow。
$pop
设该记录为array('a'=>array(0=>'haha',1=& gt;'wow'),'b'=>1)
删除某数组节点的最后一个元素:
$coll->update(
array('b'=>1),
array('$pop=>array('a'=>1)),
)
删除某数组阶段的第一个元素
$coll->update(
array('b'=>1),
array('$pop=>array('a'=>-1)),
)
$pull
如果该节点是个数组,那么删除其值为value的子项,如果不是数组,会返回一个错误。
设该记录为 array('a'=>array(0=>'haha',1=>'wow'),'b'=>1),想要删除a中value为 haha的子项:
$coll->update(
array('b'=>1),
array('$pull=>array('a'=>'haha')),
)
结果为: array('a'=>array(0=>'wow'),'b'=>1)
$pullAll
与$pull类似,只是可以删除一组符合条件的记录。
*/


5.主从+分片

shard: http://kb.cnblogs.com/page/152995/     启动服务 增删改查
mongod mongos
addshard  + enablesharding  shardCollection +   removeshard + printShardingStatus 

master-slave:http://elain.blog.51cto.com/3339379/760266/  主从一致性检测和切换
主从启动 + 状态查询 + 测试主从
slave 替换 master,停止slave,以主来重新启动
slave master 切换,主停止写,以主来重启从,获取log+关闭从,之后关闭主,用它上面的log替换主的local+master重启从,slave重启主

6.使用场景

1)mongodb介绍 : 只要关联型不强,对速度要求高的就放mongodb
    MongoDB (名称来自"humongous") 是一个可扩展的高性能,开源,模式自由,面向文档的数据库。它使用C++编写。MongoDB特点:
  a.面向集合的存储:适合存储对象及JSON形式的数据。
  b.动态查询:mongo支持丰富的查询表达方式,查询指令使用JSON形式的标记,可轻易查询文档中的内嵌的对象及数组。
  c.完整的索引支持:包括文档内嵌对象及数组。mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。
  d.查询监视:mongo包含一个监视工具用于分析数据库操作性能。
  e.复制及自动故障转移:mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目的是提供冗余及自动故障转移。
  f.高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)。
  g.自动分片以支持云级别的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器。


2)mongo使用场合 对象存储的,适用于网站缓存 均匀分布的非热点海量数据 高伸缩场景
    mongodb的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)以及传统的RDBMS系统(丰富的功能)架起一座桥梁,集两者的优势于一身。mongo适用于以下场景:
  a.网站数据:mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
  b.缓存:由于性能很高,mongo也适合作为信息基础设施的缓存层。在系统重启之后,由mongo搭建的持久化缓存可以避免下层的数据源过载。
  c.大尺寸、低价值的数据:使用传统的关系数据库存储一些数据时可能会比较贵,在此之前,很多程序员往往会选择传统的文件进行存储。
  d.高伸缩性的场景:mongo非常适合由数十或者数百台服务器组成的数据库。
  e.用于对象及JSON数据的存储:mongo的BSON数据格式非常适合文档格式化的存储及查询。


不适合的场景:事务性和复杂查询
  a.高度事物性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
  b.传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。
  c.需要SQL的问题。




3)案例:
客户信息新增功能,在新增界面上需要维护客户基本信息,客户的联系人,地址信息,客户的文档资料信息,
 * 如果不考虑非结构文档附件,整个页面本身就是一个完整的JSON对象,可以只调用一次即完成整个层次化集合对象的存储,而且相当简单。
 * 考虑到附件信息,即操作分为两个步骤,首先上传存储附件获取附件句柄ID,然后再存储结构化客户基本对象信息。
 * 对于客户拜访记录信息,录入客户拜访记录首先肯定是要选择到具体的客户,选择到具体客户后,客户的ID信息,客户的名称信息即已经可以获取到。
 * 新增加一条拜访记录也是相当简单的操作即可以完成。


再来看查询功能,首先看客户信息查询可能是一个模糊查询功能,
 * 而MongoDB对模糊查询性能是比较弱的,因此尽可能的减少不必要模糊查询字段,
 * 对于必须的查询字段可以在MongoDB对象中增加相应的索引信息。
 * 最重要的就是基于MongoDB数据库对Join操作的支持很弱,应该在数据模型设计和查询设计上尽可能的减少不必要的对象关联操作。
 * 当查询到某一个具体的客户信息后,需要查看该客户具体的拜访记录就相当简单的,只是对拜访记录表最简单的根据客户ID的一个类where操作即可完成。
 * 对于客户具体的附件列表信息可以做相似的设计,即点击链接后再进入到具体的客户附件文档查看界面。


对于更新功能,基本对象的更新也相当简单,剩下的就是对于联系人信息的更新,
 * 联系人信息是一个子集合对象,在这里暂时还没有看到是需要对这个子集合对象全部更新掉,还是可以做到只更新操作子集合对象中的一条记录。
 * 对于更新操作,仍然需要定位到具体的ID值再进行更新。对于批量更新现在MongoDB本身也提供了相应的操作,类似批量更新客户状态操作还是很容易实现的。


以上只是一个最简单的分析,基于这种分析,以后对于类似主数据管理系统的应用完全可以迁移到MongoDB数据库来支撑。
 * 另外对于记录更新不频繁,对象直接相互关联和影响小的场景也适合迁移到MongoDB数据库。
 * 在NoSQL数据库的使用过程中应该尽量避开类似强一致性要求,表间关系复杂,长周期事务等场景。
 */

0 0