MongoDB存储之GridFS

00:00/00:00

GridFS是用于存储和检索超过BSON文档大小16M限制文件的存储格式.

GridFS将文件划分为部分或者是块,而将每个块存储为一个单一的文档,而不是在一个单一的文档中存储文件.默认地,GridFS使用块的大小为255KB,也就是说:除了最后一块之外,GridFS将文件分割为255KB大小的块.最后一块的大小只使用必要的空间.同样地,不超过块大小的文件只有一个最终的块,只使用需要的空间一些额外的元数据.

GridFS使用两个集合存储文件.一个集合存储文件块,另一个存储文件的元数据.

当我们在GridFS上查询文件时,驱动将会根据需要重新分配块.我们可以在使用GridFS存储的文件上执行范围查询.我们也可以访问文件任意部分的信息,例如:”跳到”视频或音频文件的中段.

GridFS不仅仅对存储超过16MB的文件非常有用,也对于任何我们在读取文件时不想将这个文件加载到内存中的情况下非常有效.

从2.4.10版本开始修改:默认的块大小从256KB修改为255KB.

什么时候使用GridFS

在MongoDB中,是用GridFS存储大于16MB的文件.

在一些情况下,将大文件存储在MongoDB数据库中也许比直接存储在一个系统级别的文件系统中更高效:

  • 如果我们的文件系统限制了文件夹的文件数目,我们可以使用GridFS根据需要存储大量文件.
  • 当我们想要获取大文件的某个部分,但是不希望将整个文件加载到内存时,我们可以使用GridFS来获取文件的某些部分,而不用将整个文件读取到内存.
  • 当我们希望将文件和 元数据自动同步,并且在大量系统和设备上进行部署时,我们可以使用GridFS.在使用地理分离的复制集时,MongoDB可以将文件和它们的元数据自动分发到大量mongod实例和设备中.

如果我们需要自动更新整个文件的内容时,不要使用GridFS.作为可选项,我们可以存储每个文件的多个版本,并且在元数据中声明文件的当前版本.在上传了新版本文件之后,我们可以在原子更新中修改代表”最近”状态的元数据字段,必要情况下可以删除之前的版本.

更进一步,如果我们的文件都小于16MB的BSON文档大小限制,我们可以考虑在一个单一文档中手动存储文件,而不是使用GridFS.我们也可以使用BinData数据类型来存储二进制数据.

使用GridFS

如果使用GridFS存储和检索文件的话,使用下面中的任一种:

  • MongoDB驱动.
  • mongofiles命令行工具.

GridFS集合

GridFS在两个集合中存储文件:

  • chunks存储二进制块.
  • files存储文件的元数据.

GridFS通过使用桶名前缀来讲集合放置在一个共同的桶中.默认地,GridFS将两个集合放在一个名为fs的桶中:

  • fs.files
  • fs.chunks

我们可以选择一个不同的桶名,也可以在一个单一的数据库中创建多个桶,完整的集合名称,包括桶名称,也必须满足命名空间长度的限制.

chunks集合

chunks集合中的每个文档表示了GridFS中一个文件的单独块.该集合中的文档有如下形式:

  1. {
  2. "_id" : <ObjectId>,
  3. "files_id" : <ObjectId>,
  4. "n" : <num>,
  5. "data" : <binary>
  6. }

chunks集合中的一个文档包含下列字段:
– chunks._id:该chunk唯一的ObjectId
– chunks.files_id:”父”文档的_id,与files集合中声明的一样
– chunks.n:该块的序列号.GridFS对所有的块进行编号,从0开始
– chunks.data:该块的作为BSON二进制类型的数据类型.

files集合

files集合中的每个文档表示GridFS中的一个文件.考虑files集合中的一个文档,有如下形式:

  1. {
  2. "_id" : <ObjectId>,
  3. "length" : <num>,
  4. "chunkSize" : <num>,
  5. "uploadDate" : <timestamp>,
  6. "md5" : <hash>,
  7. "filename" : <string>,
  8. "contentType" : <string>,
  9. "aliases" : <string array>,
  10. "metadata" : <dataObject>,
  11. }

files集合中的文档包含部分或全部以下字段:
– files._id:该文档的唯一标示._id为我们选择的该文档的数据类型.MongoDB文档你人的数据类型是BSON ObjectId.
– files.length:文档的大小(字节为单位).
– files.chunkSize:以字节为单位每个块的大小.除了最后一块之外,GridFS将文件分割为255KB大小的块.最后一块的大小只使用必要的空间.默认大小为255KB.
– files.uploadDate:文档第一次使用GridFS存储的日期.该值为Date类型.
– files.md5:filemd5命令会返回完整文件的MD5哈希值.该值为String类型.
– files.filename:可选,GridFS文件中人们可读的名称.
– files.contentType:可选,GridFS文件的有效MIME类型.
– files.aliases:可选,别名字符串数组.
– fies.metadata:可选,我们希望存储的任何其他信息.

应用可能会创建其他随机字段.

GridFS索引

为了提高效率,GridFS在每个chunks和`files“集合中创建索引.为了方便起见,声明了GridFS的情况下,驱动将会自动创建这些索引.如果需要的话,我们也可以创建其他索引来满足应用的要求.

chunks索引

GridFS在chunks集合中使用files_id以及n字段上创建了一个唯一&复合索引.这种做法便于块的检索,如下列示例所示:

  1. db.fs.chunks.find( { files_id: myFileID } ).sort( { n: 1 } )

有GridFS声明的驱动将会在读写操作之前验证该索引是否存在.如果该索引不存在,我们可以在mongo shell中使用下面的操作来进行创建:

  1. db.fs.chunks.createIndex( { files_id: 1, n: 1 }, { unique: true } );

files索引

GridFS在files集合上使用filenameuploadDate字段创建索引.该索引便于文件的检索,如下实例所示:

  1. db.fs.files.find( { filename: myFileName } ).sort( { uploadDate: 1 } )

有GridFS声明的驱动将会在读写操作之前验证该索引是否存在.如果该索引不存在,我们可以在mongo shell中使用下面的操作来进行创建:

  1. db.fs.files.createIndex( { filename: 1, uploadDate: 1 } )

GridFS分片

使用gridfs进行分片的话需要考虑两个集合:fileschunks.

如果我们需要对一个GridFS数据库进行分片,使用chunks集合设置{ files_id : 1, n : 1 }或者{ files_id : 1}作为片键索引.

filed_id是objectid并且会自增长.
在对chunks集合进行分片时,我们不能使用哈希分片.
files集合非常小,只包含元数据.GridFS中没有任何要求的键会放置于分片环境的均匀分布中.如果我们必须对于files集合进行分片,使用_id字段,有可能的话,与一个应用字段相结合.

files集合部分保持不分片可以使得文件元数据文档存储于主分片中.

打赏

mickey

记录生活,写给几十年后的自己。