技术交流

MongoDB数据表基本操作

查看全部数据表

> use ChatRoom
switched to db ChatRoom
> show collections
Account
Chat
system.indexes
system.users

 

创建数据表

> db.createCollection("Account")
{
"ok":1}

 

> db.createCollection("Test",{capped:true, size:10000}) { "ok" : 1 }

{"ok":1}

-- 说明

capped:true,表示该集合的结构不能被修改;

size:在建表之初就指定一定的空间大小,接下来的插入操作会不断地按顺序APPEND数据在这个预分配好空间的文件中,如果已经超出空间大小,则回到文件头覆盖原来的数据继续插入。这种结构保证了插入和查询的高效性,它不允许删除单个记录,更新的也有限制:不能超过原有记录的大小。这种表效率很高,它适用于一些暂时保存数据的场合,比如网站中登录用户的session信息,又比如一些程序的监控日志,都是属于过了一定的时间就可以被覆盖的数据。

 

修改数据表名

> db.Account.renameCollection("Account1")
"ok" : 1 }

 

数据表帮助主题help


> db.Account.help()
DBCollection help
        db.Account.find().help() 
- show DBCursor help
        db.Account.count()
        db.Account.dataSize()
        db.Account.distinct( key ) 
- eg. db.Account.distinct( 'x' )
        db.Account.drop() drop the collection
        db.Account.dropIndex(name)
        db.Account.dropIndexes()
        db.Account.ensureIndex(keypattern[,options]) 
- options is an object with these possible fields: name, unique, dropDups
        db.Account.reIndex()
        db.Account.find([query],[fields]) 
- query is an optional query filter. fields is optional set of fields to return.
                                                      e.g. db.Account.find( {x:
77} , {name:1, x:1} )
        db.Account.find(...).count()
        db.Account.find(...).limit(n)
        db.Account.find(...).skip(n)
        db.Account.find(...).sort(...)
        db.Account.findOne([query])
        db.Account.findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 
'new': false] } )
        db.Account.getDB() get DB object associated with collection
        db.Account.getIndexes()
        db.Account.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )
        db.Account.mapReduce( mapFunction , reduceFunction , 
<optional params> )
        db.Account.remove(query)
        db.Account.renameCollection( newName , 
<dropTarget> ) renames the collection.
        db.Account.runCommand( name , 
<options> ) runs a db command with the given name where the first param is the collection name
        db.Account.save(obj)
        db.Account.stats()
        db.Account.storageSize() 
- includes free space allocated to this collection
        db.Account.totalIndexSize() 
- size in bytes of all the indexes
        db.Account.totalSize() 
- storage allocated for all data and indexes
        db.Account.update(query, object[, upsert_bool, multi_bool])
        db.Account.validate() 
- SLOW
        db.Account.getShardVersion() 
- only for use with sharding

 

查看全部表记录

> db.Account.find()
"_id" : ObjectId("4df08553188e444d001a763a"), "AccountID" : 1"UserName" : "libing""Password" : "1""Age" : 26"Email" : "libing@126.com""RegisterDate" : "2011-06-09 16:31:25" }
"_id" : ObjectId("4df08586188e444d001a763b"), "AccountID" : 2"UserName" : "lb""Password" : "1""Age" : 25"Email" : "libing@163.com""RegisterDate" : "2011-06-09 16:36:95" }

 

--SELECT * FROM Account

 

说明:

 

默认每页显示20条记录,当显示不下的情况下,可以用it迭代命令查询下一页数据。
可以通过DBQuery.shellBatchSize设置每页显示数据的大小。如:DBQuery.shellBatchSize = 5,这样每页就显示5条记录了。

 


> db.Test.find()
"_id" : ObjectId("4df6d55407444568af61cfea"), "TestID" : 1 }
"_id" : ObjectId("4df6d55907444568af61cfeb"), "TestID" : 2 }
"_id" : ObjectId("4df6d55b07444568af61cfec"), "TestID" : 3 }
"_id" : ObjectId("4df6d55e07444568af61cfed"), "TestID" : 4 }
"_id" : ObjectId("4df6d56207444568af61cfee"), "TestID" : 5 }
"_id" : ObjectId("4df6d56507444568af61cfef"), "TestID" : 6 }
"_id" : ObjectId("4df6d56807444568af61cff0"), "TestID" : 7 }
"_id" : ObjectId("4df6d56b07444568af61cff1"), "TestID" : 8 }
"_id" : ObjectId("4df6d56e07444568af61cff2"), "TestID" : 9 }
"_id" : ObjectId("4df6d57a07444568af61cff3"), "TestID" : 10 }
"_id" : ObjectId("4df6d57d07444568af61cff4"), "TestID" : 11 }
"_id" : ObjectId("4df6d58007444568af61cff5"), "TestID" : 12 }
"_id" : ObjectId("4df6d58307444568af61cff6"), "TestID" : 13 }
"_id" : ObjectId("4df6d58e07444568af61cff7"), "TestID" : 14 }
"_id" : ObjectId("4df6d59207444568af61cff8"), "TestID" : 15 }
"_id" : ObjectId("4df6d59607444568af61cff9"), "TestID" : 16 }
"_id" : ObjectId("4df6d59c07444568af61cffa"), "TestID" : 17 }
"_id" : ObjectId("4df6d5a307444568af61cffb"), "TestID" : 18 }
"_id" : ObjectId("4df6d5a607444568af61cffc"), "TestID" : 19 }
> DBQuery.shellBatchSize
20
> DBQuery.shellBatchSize = 5
5
> db.Test.find()
"_id" : ObjectId("4df6d55407444568af61cfea"), "TestID" : 1 }
"_id" : ObjectId("4df6d55907444568af61cfeb"), "TestID" : 2 }
"_id" : ObjectId("4df6d55b07444568af61cfec"), "TestID" : 3 }
"_id" : ObjectId("4df6d55e07444568af61cfed"), "TestID" : 4 }
"_id" : ObjectId("4df6d56207444568af61cfee"), "TestID" : 5 }
has more
> it
"_id" : ObjectId("4df6d56507444568af61cfef"), "TestID" : 6 }
"_id" : ObjectId("4df6d56807444568af61cff0"), "TestID" : 7 }
"_id" : ObjectId("4df6d56b07444568af61cff1"), "TestID" : 8 }
"_id" : ObjectId("4df6d56e07444568af61cff2"), "TestID" : 9 }
"_id" : ObjectId("4df6d57a07444568af61cff3"), "TestID" : 10 }
has more
> it
"_id" : ObjectId("4df6d57d07444568af61cff4"), "TestID" : 11 }
"_id" : ObjectId("4df6d58007444568af61cff5"), "TestID" : 12 }
"_id" : ObjectId("4df6d58307444568af61cff6"), "TestID" : 13 }
"_id" : ObjectId("4df6d58e07444568af61cff7"), "TestID" : 14 }
"_id" : ObjectId("4df6d59207444568af61cff8"), "TestID" : 15 }
has more
> it
"_id" : ObjectId("4df6d59607444568af61cff9"), "TestID" : 16 }
"_id" : ObjectId("4df6d59c07444568af61cffa"), "TestID" : 17 }
"_id" : ObjectId("4df6d5a307444568af61cffb"), "TestID" : 18 }
"_id" : ObjectId("4df6d5a607444568af61cffc"), "TestID" : 19 }
> it
no cursor

 

查询一条记录


> db.Account.findOne()
{
        
"_id" : ObjectId("4ded95c3b7780a774a099b7c"),
        
"UserName" : "libing",
        
"Password" : "1",
        
"Email" : "libing@126.cn",
        
"RegisterDate" : "2011-06-07 11:06:25"
}

--SELECT TOP 1 * FROM Account

 

 查询聚集中字段的不同记录

> db.Account.distinct("UserName")

--SELECT DISTINCT("UserName")  FROM Account

 

 查询聚集中UserName包含“keyword”关键字的记录

db.Account.find({"UserName":/keyword/})

 --SELECT * FROM Account WHERE UserName LIKE '%keyword%'

 

查询聚集中UserName以"keyword" 开头的记录

> db.Account.find({"UserName":/^keyword/})

--SELECT * FROM Account WHERE UserName LIKE 'keyword%'

 

查询聚集中UserName以“keyword”结尾的记录

> db.Account.find({"UserName":/keyword$/})

--SELECT * FROM Account WHERE UserName LIKE '%keyword' 

 

查询聚集中指定列

> db.Account.find({},{"UserName":1,"Email":1})    --1:true

--SELECT UserName,Email FROM Account

 

 查询聚集中排除指定列

> db.Account.find({},{"UserName":0})    --0:false

 

查询聚集中指定列,且Age > 20

> db.Account.find({"Age":{"$gt":20}},{"UserName":1,"Email":1})

--SELECT UserName,Email FROM Account WHERE Age > 20 

 

聚集中字段排序 

> db.Account.find().sort({"UserName":1}) -- 升序
> db.Account.find().sort({"UserName":-1}) --降序

--SELECT * FROM Account ORDER BY UserName ASC

--SELECT * FROM Account ORDER BY UserName DESC 

 

统计聚集中记录条数

> db.Account.find().count()

--SELECT COUNT(*) FROM Account 

 

统计聚集中符合条件的记录条数

> db.Account.find({"Age":{"$gt":20}}).count()

-- SELECT COUNT(*) FROM Account WHERE Age > 20

 

统计聚集中字段符合条件的记录条数

> db.Account.find({"UserName":{"$exists":true}}).count()

--SELECT COUNT(UserName) FROM Account 

 

查询聚集中前5条记录 

> db.Account.find().limit(5)

--SELECT TOP 5 * FROM Account 

 

查询聚集中第10条以后的记录

> db.Account.find().skip(10)

--SELECT * FROM Account WHERE AccountID NOT IN (SELECT TOP 10 AccountID FROM Account) 

 

查询聚集中第10条记录以后的5条记录

> db.Account.find().skip(10).limit(5)

--SELECT TOP 5 * FROM Account WHERE AccountID NOT IN (SELECT TOP 10 AccountID FROM Account)

 

or查询

> db.Account.find({"$or":[{"UserName":/keyword/},{"Email":/keyword/}]},{"UserName":true,"Email":true})

--SELECT UserName,Email FROM Account WHERE UserName LIKE '%keyword%' OR Email LIKE '%keyword%' 

 

添加新记录

> db.Account.insert({AccountID:2,UserName:"lb",Password:"1",Age:25,Email:"libing@163.com",RegisterDate:"2011-06-09 16:36:95"})

修改记录

> db.Account.update({"AccountID":1},{"$set":{"Age":27,"Email":"libingql@163.com"}})
> db.Account.find({"AccountID":1})
"AccountID" : 1"Age" : 27"Email" : "libingql@163.com""Password" : "1""RegisterDate" : "2011-06-09 16:31:25""UserName" : "libing""_id" : ObjectId("4df08553188e444d001a763a") }

 

> db.Account.update({"AccountID":1},{"$inc":{"Age":1}})
> db.Account.find({"AccountID":1})
"AccountID" : 1"Age" : 28"Email" : "libingql@163.com""Password" : "1""RegisterDate" : "2011-06-09 16:31:25""UserName" : "libing""_id" : ObjectId("4df08553188e444d001a763a") }

 

删除记录

> db.Account.remove({"AccountID":1}) --DELETE FROM Account WHERE AccountID = 1

 

> db.Account.remove({"UserName":"libing"}) --DELETE FROM Account WHERE UserName = 'libing'

 

> db.Account.remove({"Age":{$lt:20}}) --DELETE FROM Account WHERE Age < 20
> db.Account.remove({"Age":{$lte:20}}) --DELETE FROM Account WHERE Age <= 20
> db.Account.remove({"Age":{$gt:20}}) --DELETE FROM Account WHERE Age > 20
> db.Account.remove({"Age":{$gte:20}}) --DELETE FROM Account WHERE Age >= 20
> db.Account.remove({"Age":{$ne:20}}) --DELETE FROM Account WHERE Age != 20

 

> db.Account.remove()    --全部删除
> db.Account.remove({})  --全部删除

MongoDB学习

1 下载安装

安装MongoDB非常的简单,仅需下载压缩包解压运行命令即可,
下载地址:http://www.mongodb.org/downloads,本文为windows平台,
 
MongoDB运行命令:>bin/mongod
 
提示:首先要创建存储数据的文件夹,MongoDB 默认存储数据目录为 /data/db/ (或者 c:/data/db),当然你也可以修改成不同目录,只需要指定 --dbpath 参数,eg:
 
>bin/mongod --dbpath=d:/mgdata/db

 

2 建库建表

 

MongoDB创建数据库,MongoDB创建数据库,MongoDB创建数据库,MongoDB创建数据库

MongoDB创建数据库完全可以使用use

如下:

use mydb;

这样就创建了一个数据库。

这一步很重要如果什么都不操作离开的话 这个库就会被系统删除。

验证-------------------------------

然后使用插入语句:

db.usr.insert({'name':'tompig'});

db.usr.insert({'name':'tompig1','id':1});

在使用下列命令查看

show collections;  ---查看‘表’

 > show collections;
system.indexes
usr

show dbs 查看库。

> show dbs;
local   (empty)
test    0.078125GB

 

查询记录

> db.usr.find();
{ "_id" : ObjectId("4f459f01bb327e6587380b58"), "name" : "lein" }
{ "_id" : ObjectId("4f45a14dbb327e6587380b59"), "name" : "leinchu", "id" : 2 }
>

 

 

打开游览器输入URL “http://localhost:27017/”,如果出现下面的页面则说明已正常启动:

 

You are trying to access MongoDB on the native driver port. For http diagnostic access, add 1000 to the port number

http://localhost:28017/

 

3 优点和特性

使用JSON风格语法,易于掌握和理解:MongoDB使用JSON的变种BSON作为内部存储的格式和语法。针对MongoDB的操作都使用JSON风格语法,客户端提交或接收的数据都使用JSON形式来展现。相对于SQL来说,更加直观,容易理解和掌握。

Schema-less,支持嵌入子文档:MongoDB是一个Schema-free的文档数据库。一个数据库可以有多个Collection,每个Collection是Documents的集合。Collection和Document和传统数据库的Table和Row并不对等。无需事先定义Collection,随时可以创建

作品和评论可以设计为一个collection,评论作为子文档内嵌在art的comments属性中,评论的回复则作为comment子文档的子文档内嵌于replies属性。按照这种设计模式,只需要按照作品id检索一次,即可获得所有相关的信息了。在MongoDB中,不强调一定对数据进行Normalize ,很多场合都建议De-normalize,开发人员可以扔掉传统关系数据库各种范式的限制,不需要把所有的实体都映射为一个Collection,只需定义最顶级的class。MongoDB的文档模型可以让我们很轻松就能将自己的Object映射到collection中实现存储。

 

Collection中可以包含具有不同schema的文档记录。 这意味着,你上一条记录中的文档有3个属性,而下一条记录的文档可以有10个属性,属性的类型既可以是基本的数据类型(如数字、字符串、日期等),也可以是数组或者散列,甚至还可以是一个子文档(embed document)。这样,可以实现逆规范化(denormalizing)的数据模型,提高查询的速度。

 

CRUD更加简单,支持in-place update:只要定义一个数组,然后传递给MongoDB的insert/update方法就可自动插入或更新;对于更新模式,MongoDB支持一个upsert选项,即:“如果记录存在那么更新,否则插入”。MongoDB的update方法还支持Modifier,通过Modifier可实现在服务端即时更新,省去客户端和服务端的通讯。这些modifer可以让MongoDB具有和Redis、Memcached等KV类似的功能:较之MySQL,MonoDB更加简单快速。Modifier也是MongoDB可以作为对用户行为跟踪的容器。在实际中使用Modifier来将用户的交互行为快速保存到MongoDB中以便后期进行统计分析和个性化定制。

 

所有的属性类型都支持索引,甚至数组:这可以让某些任务实现起来非常的轻松。在MongoDB中,“_id”属性是主键,默认MongoDB会对_id创建一个唯一索引。

 

服务端脚本和Map/Reduce:MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。MongoDB不支持事务级别的锁定,对于某些需要自定义的“原子性”操作,可以使用Server side脚本来实现,此时整个MongoDB处于锁定状态。Map/Reduce也是MongoDB中比较吸引人的特性。Map/Reduce可以对大数据量的表进行统计、分类、合并的工作,完成原先SQL的GroupBy等聚合函数的功能。并且Mapper和Reducer的定义都是用Javascript来定义服务端脚本。

性能高效,速度快: MongoDB使用c++/boost编写,在多数场合,其查询速度对比MySQL要快的多,对于CPU占用非常小。部署也很简单,对大多数系统,只需下载后二进制包解压就可以直接运行,几乎是零配置。

支持多种复制模式: MongoDB支持不同的服务器间进行复制,包括双机互备的容错方案。

Master-Slave是最常见的。通过Master-Slave可以实现数据的备份。在我们的实践中,我们使用的是Master-Slave模式,Slave只用于后备,实际的读写都是从Master节点执行。

Replica Pairs/Replica Sets允许2个MongoDB相互监听,实现双机互备的容错。

MongoDB只能支持有限的双主模式(Master-Master),实际可用性不强,可忽略

 

内置GridFS,支持大容量的存储:这个特点是最吸引我眼球的,也是让我放弃其他NoSQL的一个原因。GridFS具体实现其实很简单,本质仍然是将文件分块后存储到files.file和files.chunk 2个collection中,在各个主流的driver实现中,都封装了对于GridFS的操作。由于GridFS自身也是一个Collection,你可以直接对文件的属性进行定义和管理,通过这些属性就可以快速找到所需要的文件,轻松管理海量的文件,无需费神如何hash才能避免文件系统检索性能问题, 结合下面的Auto-sharding,GridFS的扩展能力是足够我们使用了。在实践中,我们用MongoDB的GridFs存储图片和各种尺寸的缩略图

 

内置Sharding,提供基于Range的Auto Sharding机制:一个collection可按照记录的范围,分成若干个段,切分到不同的Shard上。Shards可以和复制结合,配合Replica sets能够实现Sharding+fail-over,不同的Shard之间可以负载均衡。查询是对客户端是透明的。客户端执行查询,统计,MapReduce等操作,这些会被MongoDB自动路由到后端的数据节点。这让我们关注于自己的业务,适当的时候可以无痛的升级。MongoDB的Sharding设计能力最大可支持约20 petabytes,足以支撑一般应用。

第三方支持丰富: MongoDB社区非常活跃,很多开发框架都迅速提供了对MongDB的支持。不少知名大公司和网站也在生产环境中使用MongoDB,越来越多的创新型企业转而使用MongoDB作为和Django,RoR来搭配的技术方案。

 

实施MonoDB的过程是令人愉快的。我们对自己的PHP开发框架进行了修改以适应MongoDB。在PHP中,对MongoDB的查询、更新都是围绕Array进行的,实现代码变得很简洁。由于无需建表,MonoDB运行测试单元所需要的时间大大缩短,对于TDD敏捷开发的效率也提高了。当然,由于MongoDB的文档模型和关系数据库有很大不同,在实践中也有很多的困惑,幸运的是,MongoDB开源社区给了我们很大帮助。最终,我们使用了2周就完成了从MySQL到MongoDB的代码移植比预期的开发时间大大缩短。从我们的测试结果看也是非常惊人,数据量约2千万,数据库300G的情况下,读写2000rps,CPU等系统消耗是相当的低(我们的数据量还偏小,目前陆续有些公司也展示了他们的经典案例:MongoDB存储的数据量已超过 50亿,>1.5TB)。目前,我们将MongoDB和其他服务共同部署在一起,大大节约了资源。

一些小提示

切实领会MongoDB的Document模型,从实际出发,扔掉关系数据库的范式思维定义,重新设计类;在服务端运行的JavaScript代码避免使用遍历记录这种耗时的操作,相反要用Map/Reduce来完成这种表数据的处理;属性的类型插入和查询时应该保持一致。若插入时是字符串“1”,则查询时用数字1是不匹配的;优化MongoDB的性能可以从磁盘速度和内存着手;MongoDB对每个Document的限制是最大不超过4MB;在符合上述条件下多启用Embed Document, 避免使用DatabaseReference;内部缓存可以避免N+1次查询问题(MongoDB不支持joins)。

 

 

用Capped Collection解决需要高速写入的场合,如实时日志;大数据量情况下,新建同步时要调高oplogSize的大小,并且自己预先生成数据文件,避免出现客户端超时;Collection+Index合计数量默认不能超过24000;当前版本(<v1.6)删除数据的空间不能被回收,如果你频繁删除数据,那么需要定期执行repairDatabase,释放这些空间。

 

 

-----------------------------------------------------

 

MongoDB授权和权限

  官方文档开启MongoDB 服务时不添加任何参数时,可以对数据库任意操作,而且可以远程访问数据库,所以推荐只是在开发是才这样不设置任何参数。如果启动的时候指定--auth参数,可以从阻止根层面上的访问和连接

 

  (1)、只允许某ip访问

  mongod --bind_ip 127.0.0.1

  (2)、指定服务端口

  mongod --bind_ip 127.0.0.1 --port27888

  (3)、添加用户认证

  mongod --bind_ip 127.0.0.1 --port27888 –auth

  (4)、添加用户

  在刚安装完毕的时候MongoDB都默认有一个admin数据库,而admin.system.users中将会保存比在其它数据库中设置的用户权限更大的用户信息。

  当admin.system.users中一个用户都没有时,即使mongod启动时添加了--auth参数,如果没有在admin数据库中添加用户,此时不进行任何认证还是可以做任何操作,直到在admin.system.users中添加了一个用户。

  下面分别创建两个用户, 在foo中创建用户名为user1密码为pwd1的用户,如下:

 

[root@localhost bin]# ./mongo --port 27888 
MongoDB shell version: 1.8.1 
connecting to: test 
> use foo 
switched to db foo 
> db.addUser("user1","pwd1") 

        "user" : "user1", 
        "readOnly" : false, 
        "pwd" : "35263c100eea1512cf3c3ed83789d5e4" 
}

  在admin中创建用户名为root密码为pwd2的用户,如下:

> use admin 
switched to db admin 
> db.addUser("root", "pwd2") 

        "_id" : ObjectId("4f8a87bce495a88dad4613ad"), 
        "user" : "root", 
        "readOnly" : false, 
        "pwd" : "20919e9a557a9687c8016e314f07df42" 

> db.auth("root", "pwd2") 

>

在admin库建立的用户对所有库有权限,而在指定库的就只能在指定库有权限

 

  (1)、mongoexport导出工具

  MongoDB提供了mongoexport工具,可以把一个collection导出成json格式或csv格式的文件。可以指定导出哪些数据项,也可以根据给定的条件导出数据。工具帮助信息如下:

[root@localhost bin]# ./mongoexport --help 
options: 
  --help                  produce help message 
  -v [ --verbose ]        be more verbose (include multiple times for more  
                          verbosity e.g. -vvvvv) 
  -h [ --host ] arg       mongo host to connect to ( <set name>/s1,s2 for sets) 
  --port arg              server port. Can also use --host hostname:port 
  --ipv6                  enable IPv6 support (disabled by default) 
  -u [ --username ] arg   username 
  -p [ --password ] arg   password 
  --dbpath arg            directly access mongod database files in the given  
                          path, instead of connecting to a mongod  server -  
                          needs to lock the data directory, so cannot be used  
                          if a mongod is currently accessing the same path 
  --directoryperdb        if dbpath specified, each db is in a separate  
                          directory 
  -d [ --db ] arg         database to use 
  -c [ --collection ] arg collection to use (some commands) 
  -f [ --fields ] arg     comma separated list of field names e.g. -f name,age 
  --fieldFile arg         file with fields names - 1 per line 
  -q [ --query ] arg      query filter, as a JSON string 
  --csv                   export to csv instead of json 
  -o [ --out ] arg        output file; if not specified, stdout is used 
  --jsonArray             output to a json array rather than one object per  
                          line 
[root@localhost bin]#

 

  下面我们将以一个实际的例子说明,此工具的用法:

  将foo库中的表t1导出成json格式:

[root@localhost bin]# ./mongoexport -d foo -c t1 -o /data/t1.json 
connected to: 127.0.0.1 
exported 1 records 
[root@localhost bin]#

 

  导出成功后我们看一下/data/t1.json文件的样式,是否是我们所希望的:

[root@localhost data]# more t1.json  
{ "_id" : { "$oid" : "4f927e2385b7a6814a0540a0" }, "age" : 2 } 
[root@localhost data]#

 

  通过以上说明导出成功,但有一个问题,要是异构数据库的迁移怎么办呢?例如我们要将MongoDB的数据导入到MySQL该怎么办呢?MongoDB提供了一种csv的导出格式,就可以解决异构数据库迁移的问题了. 下面将foo库的t2表的age和name列导出, 具体如下:

[root@localhost bin]# ./mongoexport -d foo -c t2 --csv -f age,name -o /data/t2.csv  
connected to: 127.0.0.1 
exported 1 records 
[root@localhost bin]#

 

  查看/data/t2.csv的导出结果:

[root@localhost data]# more t2.csv 
age,name 
1,"wwl" 
[root@localhost data]#

 

  可以看出MongoDB为我们提供了一个强在的数据导出工具。

  (2)、mongoimport导入工具

  MongoDB提供了mongoimport工具,可以把一个特定格式文件中的内容导入到某张collection中。工具帮助信息如下:

 

[root@localhost bin]# ./mongoimport --help 
options: 
  --help                  produce help message 
  -v [ --verbose ]        be more verbose (include multiple times for more  
                          verbosity e.g. -vvvvv) 
  -h [ --host ] arg       mongo host to connect to ( <set name>/s1,s2 for sets) 
  --port arg              server port. Can also use --host hostname:port 
  --ipv6                  enable IPv6 support (disabled by default) 
  -u [ --username ] arg   username 
  -p [ --password ] arg   password 
  --dbpath arg            directly access mongod database files in the given  
                          path, instead of connecting to a mongod  server -  
                          needs to lock the data directory, so cannot be used  
                          if a mongod is currently accessing the same path 
  --directoryperdb        if dbpath specified, each db is in a separate  
                          directory 
  -d [ --db ] arg         database to use 
  -c [ --collection ] arg collection to use (some commands) 
  -f [ --fields ] arg     comma separated list of field names e.g. -f name,age 
  --fieldFile arg         file with fields names - 1 per line 
  --ignoreBlanks          if given, empty fields in csv and tsv will be ignored 
  --type arg              type of file to import.  default: json (json,csv,tsv) 
  --file arg              file to import from; if not specified stdin is used 
  --drop                  drop collection first  
  --headerline            CSV,TSV only - use first line as headers 
  --upsert                insert or update objects that already exist 
  --upsertFields arg      comma-separated fields for the query part of the  
                          upsert. You should make sure this is indexed 
  --stopOnError           stop importing at first error rather than continuing 
  --jsonArray             load a json array, not one item per line. Currently  
                          limited to 4MB.

  下面我们将以一人实际的例子说明,此工具的用法:

  先看一下foo库中的t1表数据:

> db.t1.find(); 
{ "_id" : ObjectId("4f937a56450beadc560feaa9"), "age" : 5 } 
>

  t1其中有一条age=5的记录, 我们再看一下json文件中的数据是什么样子的:

[root@localhost data]# more t1.json  

{ "_id" : { "$oid" : "4f937a56450beadc560feaa7" }, "age" : 8 }     

[root@localhost data]#

  可以看到t1.json文件中有一条age=8的数据,下面我们将用mongoimport工具将json文件中的记录导入到t1表中:

[root@localhost bin]# ./mongoimport -d foo -c t1 /data/t1.json  
    
connected to: 127.0.0.1  
   
imported 1 objects

  工具返回信息说明向表中插入了一条记录. 我们进库里实际验证一下:

[root@localhost bin]# ./mongo 
MongoDB shell version: 1.8.1 
connecting to: test 
> use foo 
switched to db foo 
> db.t1.find(); 
{ "_id" : ObjectId("4f937a56450beadc560feaa9"), "age" : 5 } 
{ "_id" : ObjectId("4f937a56450beadc560feaa7"), "age" : 8 } 
>

 结果跟我们期待的是一样的,数据成功插入到表中。

MongoDB备份和恢复

  MongoDB提供了两个命令来备份(mongodump )和恢复(mongorestore )数据库。

查看linux文件目录的大小和文件夹包含的文件数

查看linux文件目录的大小和文件夹包含的文件数

    统计总数大小

    du -sh xmldb/

    du -sm * | sort -n //统计当前目录大小 并安大小 排序

    du -sk * | sort -n

    du -sk * | grep guojf //看一个人的大小

    du -m | cut -d "/" -f 2 //看第二个/ 字符前的文字

    查看此文件夹有多少文件 /*/*/* 有多少文件

    du xmldb/

    du xmldb/*/*/* |wc -l

    40752

    解释:

    wc [-lmw]

    参数说明:

    -l :多少行

    -m:多少字符

    -w:多少字

mysql中“Table ‘’ is read only”的解决办法

之前是在linux下面直接Copy的data下面整个数据库文件夹,在phpMyAdmin里面重新赋予新用户相应权限后,drupal成功连接上数据库。但出现N多行错误提示,都是跟Cache相关的表是‘Read only‘,而且phpMyAdmin里面优化表也是提示”Table ‘xxx’ is read only“。
我怀疑是文件权限的问题,所以将该数据库文件夹下面所有表文件chmod成777,chown成”_mysql”,但这次问题更严重,drupal里面现实table crached。没办法,马上Google,发现其实解决起来挺容易的。

首先,找到mysqladmin所在位置,一般都在mysql/bin下面,然后运行一下命令:

./mysqladmin -u root -p flush-tables

之后输入root账号的密码,马上就好了,没有任何任何提示,重新打开drupal,一切正常。

通过这次,也找到了数据库文件的正确权限设置:data下面数据库文件夹700,表文件660,所有文件都应owned by mysql。

PHP抓取网页图片

<?php
 set_time_limit(0);//抓取不受时间限制
 if($_POST['Submit']=="开始抓取"){
  $URL=$_POST['link'];
  get_pic($URL);
 }
 function get_pic($pic_url) {
  //获取图片二进制流
  $data=CurlGet($pic_url);
  //利用正则表达式得到图片链接
  $pattern_src1 = '/<img.*?src\=\"(.*\.jpg).*?>/';//只匹配jpg格式的图片
  $pattern_src2 = '/<img.*?src\=\"(.*\.bmp).*?>/';//只匹配bmp格式的图片
  $pattern_src3 = '/<img.*?src\=\"(.*\.png).*?>/';//只匹配png格式的图片
  $pattern_src4 = '/<img.*?src\=\"(.*\.gif).*?>/';//只匹配gif格式的图片
  $num1 = preg_match_all($pattern_src1, $data, $match_src1);
  $num2 = preg_match_all($pattern_src2, $data, $match_src2);
  $num3 = preg_match_all($pattern_src3, $data, $match_src3);
  $num4 = preg_match_all($pattern_src4, $data, $match_src4);
  $arr_src1=$match_src1[1];//获得图片数组
  $arr_src2=$match_src2[1];
  $arr_src3=$match_src3[1];
  $arr_src4=$match_src4[1];
  echo '=============================================抓取开始=============================================<br />';
  get_name1($arr_src1);
  get_name1($arr_src2);
  get_name1($arr_src3);
  get_name1($arr_src4);
  get_name2($arr_src1);
  get_name2($arr_src2);
  get_name2($arr_src3);
  get_name2($arr_src4);
  
  echo '=============================================抓取结束=============================================<br />';
  return 0;
 }
 
 function get_name1($pic_arr){
  //图片编号和类型
  $pattern_type = '/.*\/(.*?)$/';
  
  foreach($pic_arr as $pic_item){//循环取出每幅图的地址
   $num = preg_match_all($pattern_type,$pic_item,$match_type);
   //以流的形式保存图片
   $write_fd = @fopen($match_type[1][0],"wb");
   echo "图片网址:<a href='".$pic_item."' target='_blank'>".$pic_item."</a><br />";
   @fwrite($write_fd, CurlGet($pic_item));
   @fclose($write_fd);
  }
  return 0;
 }
  function get_name2($pic_arr){
  //图片编号和类型
  $pattern_type = '/.*\/(.*?)$/';
  
  foreach($pic_arr as $pic_item){//循环取出每幅图的地址
   $num = preg_match_all($pattern_type,$pic_item,$match_type);
   //以流的形式保存图片
   $write_fd = @fopen($match_type[1][0],"wb");
   echo "图片网址:<a href='".$_POST['link'].$pic_item."' target='_blank'>".$_POST['link'].$pic_item."</a><br />";
   @fwrite($write_fd, CurlGet($_POST['link'].$pic_item));
   @fclose($write_fd);
  }
  return 0;
 }
 //抓取网页内容
 function CurlGet($url){ 
  $url=str_replace('&amp;','&',$url);
  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_HEADER, false);
  
  //curl_setopt($curl, CURLOPT_REFERER,$url);
  curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; SeaPort/1.2; Windows NT 5.1; SV1; InfoPath.2)");
  curl_setopt($curl, CURLOPT_COOKIEJAR, 'cookie.txt');
  curl_setopt($curl, CURLOPT_COOKIEFILE, 'cookie.txt');
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 0);
  $values = curl_exec($curl);
  curl_close($curl);
  return $values;
 }
?>
<html>
 <head>
  <title>网页图片抓取</title>
 </head>
 <body>
  <form action="" method="post">
   要抓取图片的网址:<input type="text" id="link" name="link" value="请在这里输入要抓取图片的网址" OnClick="this.value=''" size="100" /><br />
   <input type="submit" id="Submit" name="Submit" value="开始抓取" />
  </form>
 </body>
</html>

couldn't resolve host api.weixin.qq.com

从这个报错,可以很明显的发现是域名解析不了。于是做如下排查。 
1. 故障排除 
1. 1 测试域名是否能解析到 
简单的使用ping来测试,发现DNS解析是否OK。

ping -c 1 api.weixin.qq.com


1.2 测试curl是否有故障 
因为php程序调用的是curl,所以我们测试一下curl是否能够正常解析dns 
curl  api.weixin.qq.com 
竟然真的不行, 
2. 解决问题 
尝试解决方法: 
修改dns 
cat /etc/resolv.conf | grep names 
nameserver 114.114.114.114

nameserver 8.8.8.8 
重新测试curl,问题得到解决。 
修改/etc/resolv.conf又恢复到原来的状态? 
设置一次可以,过一会或者重启一下服务器,重启一下network都不能解析了。发现/etc/resolv.conf又恢复到原来的状态,里面什么都没有了。手动加入nameserver也不行。 
后来到网上查找,发现有人与我同样的问题。原来在CentOS5.4下面直接修改/etc/resolv.conf不行。必须要在/etc /sysconfig/network-scripts/ifcfg-eth0里面最后加上dns的设置。要不然,重启后,肯定使用eth0设置中没有设 dns的相关信息,使/etc/resolv.conf恢复到原来的状态。 
打开/etc/sysconfig/network-scripts/ifcfg-eth0,为了保险起见,可以同样修改eth1的设置 
DEVICE=eth0 
  BOOTPROTO=none 
  HWADDR=00:xx:19:xx:xx:xx 
  ONBOOT=yes 
  TYPE=Ethernet 
  USERCTL=no 
  IPV6INIT=no 
  PEERDNS=yes 
  NETMASK=255.255.255.0 
  IPADDR=xxx.xxx.xxx.xxx 
  GATEWAY=xxx.xxx.xxx.xxx 
  DNS1=202.96.209.5 #上海dns,根据实际情况更换 
  DNS2=202.96.209.133 #上海dns,根据实际情况更换 
这样设置后,/etc/resolv.conf里面根本就不需要设置。service network restart 后,可以发现/etc/resolv.conf里面就有两个dns的解析ip了。配置好以后重启网络,cat /etc/resolv.conf,可以看到如下参数: 
# Generated by NetworkManager 
  nameserver 202.96.209.5 
  nameserver 202.96.209.133 
  search localdomain 
DNS解析设置成功。 
  在此要强调一点的是,直接修改/etc/resolv.conf这个文件是没用的,网络服务重启以后会根据/etc/sysconfig /network-scripts/ifcfg-eth0来重载配置,如果ifcfg-eth0没有配置DNS,那么resolv.conf会被冲掉,重 新变成空值。

PHP中读取文件的几个方法

整理了一下PHP中读取文件的几个方法,方便以后查阅。
1.fread
  string fread ( int $handle , int $length )
  fread() 从 handle 指向的文件中读取最多 length 个字节。该函数在读取完最多 length 个字节数,或到达 EOF 的时候,或(对于网络流)当一个包可用时,或(在打开用户空间流之后)已读取了 8192 个字节时就会停止读取文件,视乎先碰到哪种情况。
  fread() 返回所读取的字符串,如果出错返回 FALSE。
复制代码
<?php
    $filename = "/usr/local/something.txt";
    $handle = fopen($filename, "r");//读取二进制文件时,需要将第二个参数设置成'rb'
    
    //通过filesize获得文件大小,将整个文件一下子读到一个字符串中
    $contents = fread($handle, filesize ($filename));
    fclose($handle);
?>
复制代码

  如果所要读取的文件不是本地普通文件,而是远程文件或者流文件,就不能用这种方法,因为,filesize不能获得这些文件的大小。此时,你需要通过feof()或者fread()的返回值判断是否已经读取到了文件的末尾。
  例如:
复制代码
<?php
    $handle = fopen('http://www.baidu.com', 'r');
    $content = '';
    while(!feof($handle)){
        $content .= fread($handle, 8080);
    }
    echo $content;
    fclose($handle);
?>
复制代码
或者:
复制代码
<?php
    $handle = fopen('http://www.baidu.com', 'r');
    $content = '';
    while(false != ($a = fread($handle, 8080))){//返回false表示已经读取到文件末尾
        $content .= $a;
    }
    echo $content;
    fclose($handle);
?>
复制代码
 
2.fgets
  string fgets ( int $handle [, int $length ] )
  fgets()从 handle 指向的文件中读取一行并返回长度最多为 length - 1 字节的字符串。碰到换行符(包括在返回值中)、EOF 或者已经读取了 length - 1 字节后停止(看先碰到那一种情况)。如果没有指定 length,则默认为 1K,或者说 1024 字节。
复制代码
<?php
    $handle = fopen('./file.txt', 'r');
    while(!feof($handle)){
        echo fgets($handle, 1024);
    }
    fclose($handle);
?>
复制代码
  Note: length 参数从 PHP 4.2.0 起成为可选项,如果忽略,则行的长度被假定为 1024。从 PHP 4.3 开始,忽略掉 length 将继续从流中读取数据直到行结束。如果文件中的大多数行都大于 8KB,则在脚本中指定最大行的长度在利用资源上更为有效。从 PHP 4.3 开始本函数可以安全用于二进制文件。早期的版本则不行。

3.fgetss
  string fgetss ( resource $handle [, int $length [, string $allowable_tags ]] )
  跟fgets功能一样,但是fgetss会尝试从读取的文本中去掉任何 HTML 和 PHP 标记,可以用可选的第三个参数指定哪些标记不被去掉。
复制代码
<?php
    $handle = fopen('./file.txt', 'r');
    while(!feof($handle)){
        echo fgetss($handle, 1024, '<br>');
    }
    fclose($handle);
?>
复制代码
 
4.file
  array file ( string $filename [, int $use_include_path [, resource $context ]] )
  将文件内容读入一个数组中,数组的每一项对应文件中的一行,包括换行符在内。不需要行结束符时可以使用 rtrim() 函数过滤换行符。
复制代码
<?php
    $a = file('./file.txt');
    foreach($a as $line => $content){
        echo 'line '.($line + 1).':'.$content;
    }
?>
复制代码

 5.readfile
  int readfile ( string $filename [, bool $use_include_path [, resource $context ]] )
  读入一个文件并写入到输出缓冲。返回从文件中读入的字节数。如果出错返回 FALSE 并且除非是以 @readfile() 形式调用,否则会显示错误信息。
<?php
    $size = readfile('./file.txt');
    echo $size;
?>
 
6.file_get_contents
  string file_get_contents ( string $filename [, bool $use_include_path [, resource $context [, int $offset [, int $maxlen ]]]] )
  将文件读入一个字符串。第三个参数$context可以用来设置一些参数,比如访问远程文件时,设置超时等等。
  另外,file_get_contents相对于以上几个函数,性能要好得多,所以应该优先考虑使用file_get_contents。但是readfile貌似比file_get_contents性能好一点(?),因为它不需要调用fopen。
复制代码
<?php 
    $ctx = stream_context_create(array( 
        'http' => array( 
            'timeout' => 1    //设置超时
            ) 
        ) 
    ); 
    echo file_get_contents("http://www.baidu.com/", 0, $ctx); 
?>
复制代码

7.fpassthru
   int fpassthru ( resource $handle )
  将给定的文件指针从当前的位置读取到 EOF 并把结果写到输出缓冲区。
复制代码
<?php 
    header("Content-Type:text/html;charset=utf-8"); 
    $handle = fopen('./test2.php', 'r');
    fseek($handle, 1024);//将指针定位到1024字节处
    fpassthru($handle);
?>
复制代码
 
8.parse_ini_file
  array parse_ini_file ( string $filename [, bool $process_sections ] )
  parse_ini_file() 载入一个由 filename 指定的 ini 文件,并将其中的设置作为一个联合数组返回。如果将最后的 process_sections 参数设为 TRUE,将得到一个多维数组,包括了配置文件中每一节的名称和设置。process_sections 的默认值是 FALSE。
  注意:
1. 如果 ini 文件中的值包含任何非字母数字的字符,需要将其括在双引号中(")。
2. 有些保留字不能作为 ini 文件中的键名,包括:null,yes,no,true 和 false。值为 null,no 和 false 等效于 "",值为 yes 和 true 等效于 "1"。字符 {}|&~![()" 也不能用在键名的任何地方,而且这些字符在选项值中有着特殊的意义。
test.ini文件内容:
复制代码
; This is a sample configuration file
; Comments start with ';', as in php.ini

[first_section]
one = 1
five = 5
animal = BIRD

[second_section]
path = "/usr/local/bin"
URL = "http://www.example.com/~username
复制代码
test.php内容:
<?php 
    $config = parse_ini_file('./test.ini', ture);
    print_r($config);
?>
输出内容:
复制代码
Array
(
    [first_section] => Array
        (
            [one] => 1
            [five] => 5
            [animal] => BIRD
        )

    [second_section] => Array
        (
            [path] => /usr/local/bin
            [URL] => http://www.example.com/~username
        )

)
复制代码
 
 
 
几个注意事项:
  1. 鼓励在处理二进制文件时使用 b 标志,即使系统并不需要,这样可以使脚本的移植性更好。 
  2. allow_url_fopen选项激活了 URL 形式的 fopen 封装协议使得可以访问 URL 对象例如文件。默认的封装协议提供用 ftp 和 http 协议来访问远程文件,一些扩展库例如 zlib 可能会注册更多的封装协议。出于安全性考虑,此选项只能在 php.ini 中设置。
  3. 如果要打开有特殊字符的 URL (比如说有空格),就需要使用 urlencode() 进行 URL 编码。

记事狗微博在Nginx服务器下的伪静态规则

location / {        index index.html index.php;        if (-f $request_filename/index.html){            rewrite (.*) $1/index.html break;        }        if (-f $request_filename/index.php){            rewrite (.*) $1/index.php;        }        if (!-f $request_filename){            rewrite (.*) /index.php;        }    }
Total: 179Page 4 of 23‹ Prev1234567Next ›Last »