翻译自 : http://gihyo.jp/dev/serial/01/mongodb/0007   本文永久链接地址:https://www.askmaclean.com/archives/mongodb-gridfs.html

 

GridFS的概要

  能在MongoDB中保存的Document尺寸一般有最大16Mbyte的限制。这对于保存一般的文本文件是非常足够的尺寸,但要保存一些巨大的文本文件以及视频等Binary data时,就会出现超出16Mbyte的情况。想在MongoDB中保存16Mbyte以上的文件时,通过使用GridFS这种接口,可以将数据进行多个分割来进行保存。这次,我将解说处理MongoDB中处理大尺寸文件的功能——GridFS。   GridFS的概要图       图:左青:大文件 左蓝:girdFS interface(mongofile或者是driver) 黄:1.将文件分割到chunk中,写入文件。 2.文件的元数据(文件名、尺寸等等)的写入 上图例:文件 collection 右Mongod以下:chunk用collection、Binary data、Binary data、Binary data、元数据用collection、元数据。   被分割的数据我们称之为chunk,作为Binary data保存在Document中。

 

用数据库来管理文件的优点

  话说回来,用数据库管理文件有怎样的好处呢。   在大部分系统之中,图片/音频/视频等大尺寸Binary data使用OS的文件系统进行保存。使用文件系统的话,就能用用习惯的接口访问文件。但是根据情况不同,文件被保存在数据库中,管理起来就会更有效率。以下我试着整理了用数据库来管理文件的优点。

 元数据管理简便

  不仅是文件,也能通过数据库对文件相关的元数据进行同时管理。比如,文件的尺寸与制成者,制成时间等。视频文件的话也可以管理播放次数。在数据库中与文件相关的元数据也非常简便,有扩张性。另外,包含元数据的备份也很容易。

不受文件系统的上限限制

  在OS中,对文件数以及目录数有上限。比如,ext3的情况下,目录内的子目录以及文件数的上限是32000。

试着简单操作下gridFS吧

  在MongoDB中使用GridFS不需要特别的设定以及使用方法。基于Replica set/ sharding也可以使用。那么让我们来试着使用GridFS在MongoDB中保存文件吧。   这次我们使用在MongoDB标准版准备的Command-line tool——mongofiles。命令的选项我们将在下章进行详细说明。   首先作成用1MB.file这个文件名保存的文件。在下面的例子中作成文件尺寸1MB。  
$ dd if=/dev/zero of=1MB.file bs=1M count=1
  使用mongofiles,在girdtest这个数据库中保存刚刚制成的1MB的file。  
$ mongofiles -v -d gridtest put 1MB.file
Wed Feb 20 15:23:27 creating new connection to:127.0.0.1:27017
Wed Feb 20 15:23:27 BackgroundJob starting: ConnectBG
Wed Feb 20 15:23:27 connected connection!
connected to: 127.0.0.1
added file: { _id: ObjectId('51246bdfa3264162c8e99716'), 
filename: "1MB.file", chunkSize: 262144, 
uploadDate: new Date(1361341409698), 
md5: "b6d81b360a5672d80c27430f39153e2c", 
length: 1048576 }
done!
  运行结果如上所示的话就代表保存成功了。    

关于collection结构

让我们从mongo shell开始确认GridFS的collection吧。连接mongoDB选择girdtest数据库。 $ mongo> use gridtest     确认collection。 > show collectionsfs.chunksfs.filessystem.indexes   Index之外,也有fs.chunks以及fs.files这样的collection。各自的功能分别如下所示。   fs.chunks   GridFS中,将文件作为chunk在一定尺寸中分割,保存在fs.chunks collection中。分割文件的默认尺寸是256KB。   fs.files   在fs.files collection中保存着文件名、上传时间,MD5 hash信息、文件尺寸等元数据。可以追加任意元数据。 关于被保存的元数据在官方document中有详细信息。 在下一章中,我将说明GridFS的两种操作方法:mongofiles以及ruby driver。  

使用mongofiles的GridFS的操作

  Mongofile是MongoDB标准版中准备的命令行工具。在安装了MongoDB的目录的bin之中。使用这个mongofiles,来试着操作GridFS吧。   各命令共通的命令行工具   V选项输出了详细内容 用d选项指定数据库名  

追加文件

  要追加文件就应该使用put。在此,我们在gridtest数据库中追加1MB.file这个文件。 $ mongofiles -v -d gridtest put 1MB.file 即使用同样文件名追加的,只要不被覆盖,就能作为别的object来追加。覆盖的情况时,请指定-r 选项。 $ mongofiles -v -d gridtest -r put 1MB.file

取得文件

  文件的取得请使用get $ mongofiles -v -d gridtest get 1MB.file   有同样文件名的情况,可以取得之后追加的项目。     文件的list表示   要将文件表示成表,请使用list。可以显示文件名以及文件尺寸。有同样文件名的情况下,被表示成复数。在下例中,1MB.file这个名字的文件记录了2个。  
$ mongofiles -v -d gridtest list
Wed Feb 20 16:08:01 creating new connection to:127.0.0.1:27017
Wed Feb 20 16:08:01 BackgroundJob starting: ConnectBG
Wed Feb 20 16:08:01 connected connection!connected to: 127.0.0.1
1MB.file        1048576
1MB.file        1048576
image01.png     524288
image02.png     262144
 

删除文件

  文件的删除使用delete。。   [注意]   同样文件名的数据会被全部删除,请大家注意。 $ mongofiles -v -d gridtest delete 1MB.file

文件搜索

  文件的搜索使用search。指定的文字列包含文件名的情况下,会被显示。 $ mongofiles -v -d gridtest search 1MB

使用ruby的GridFS的操作

  通过使用 ruby用MongoDB官方driver,可以从Ruby操作GridFS。Driver可以从gem开始安装。 $ gem install mongo   虽然不是必要的,同样地在gem中安装bson_ext的话,可以实现BSON处理的高速化。 $ gem install bson_ext   首先进行准备。要从Ruby中处理GridFS的话,需要在fs.chunks中制成index。通过在mongofiles中登陆文件,可以自动制成index。 $ dd if=/dev/zero of=1MB.file bs=1M count=1$ mongofiles -d gridtest put 1MB.file   以下是对于gridtest数据库进行取得与保存,最后删除的脚本。追加文件时,可以登陆任意元文件。
require  'mongo'

db_name = "gridtest"
@con = Mongo::Connection.new
@db = @con[db_name]
@grid = Mongo::Grid.new(@db)
@collection = @db["fs.files"]


file_id = @grid.put(File.binread("1MB.file"),
                    :filename => "1MB.file",
                    :tags => ["mongo","database","book"],
                    :memo => "sample file",
                    :owner => "mongonouchi")

puts "get file_id=#{file_id}"
puts "filename = #{@grid.get(file_id).filename}"
puts ""

@collection.find({:_id => BSON::ObjectId(file_id.to_s)}).each{ |doc|
  puts doc.inspect
}

puts ""
puts "delete file_id=#{file_id}"
@grid.delete(file_id)
    上述作为grid_sample.rb保存,以下是输出例。为了大家方便看,我分行写的。被输出的file_id根据环境发生改变。  
$ ruby grid_sample.rb
get file_id=512ac8a2af1fe66a0e000001
filename = 1MB.file

{"_id"=>BSON::ObjectId('512ac8a2af1fe66a0e000001'), 
 "filename"=>"1MB.file", 
 "contentType"=>"binary/octet-stream", 
 "length"=>1048576, 
 "chunkSize"=>262144, 
 "uploadDate"=>2013-02-25 02:12:50 UTC, 
 "md5"=>"b6d81b360a5672d80c27430f39153e2c", 
 "tags"=>["mongo", "database", "book"], 
 "memo"=>"sample file", 
 "owner"=>"mongonouchi"
}

delete file_id=512ac8a2af1fe66a0e000001
   

 其他工具

  Mongofiles,在官方driver中也开发了其他能操作GridFS的工具。在此我们省略详细接受,有从Nginx开始直接GridFS操作的nginx-gridfs

下次的主题

  这次介绍了在MongoDB中处理大尺寸文件的GridFS。通过使用GridFS,图片以及动画等大文件也可以通过MongoDB来进行管理。 下次我想介绍就快发售的MongoDBv2.4的新功能。在MongoDB中追加了全文搜索,GeoJSON对应,hash document等先进功能。请大家多多期待。