MongoDB 学习笔记十二 GridFS、固定集合、自动增长、释放磁盘空间

MongoDB 学习笔记十二 GridFS、固定集合、自动增长

  • MongoDB GridFS
    • GridFS 添加文件
    • MongoDB 固定集合(Capped Collections)
    • 创建固定集合
    • 固定集合查询
    • 固定集合的功能特点
    • 固定集合属性及用法
  • MongoDB 自动增长
    • 使用 counters 集合
    • 创建 Javascript 函数
    • 使用 Javascript 函数
  • 释放磁盘空间
    • 修复数据库命令
    • 使用 dump & restore 方式

MongoDB GridFS

GridFS 用于存储和恢复哪些超过 16M(BSON文件限制)的文件(如:图片、音频、视频等)

GridFS 也是文件存储的一种方式,但是他是存储在 MongoDB 的集合中。

GirdFS 可以更好的存储大于 16 M 文件。

GridFS 会将大文件对象分割成多个小的 chunk(文件片段),一般为 256K/个,每个 chunk 将作为 MongoDB 的一个文档(document)被存储在 chunks 集合中。

GridFS 用两个集合来存储一个文件:fs.files 与 fs.chunks。

每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的 meta 数据(filename、content_type,还有用户自定义的属性)将会被存在 files 集合中。以下是简单的 fs.files 集合文档:

{
   "filename": "test.txt",
   "chunkSize": NumberInt(261120),
   "uploadDate": ISODate("2014-04-13T11:32:33.557Z"),
   "md5": "7b762939321e146569b07f72c62cca4f",
   "length": NumberInt(646)
}

以下是简单的 fs.chunks 集合文档:

{
   "files_id": ObjectId("534a75d19f54bfec8a2fe44b"),
   "n": NumberInt(0),
   "data": "Mongo Binary Data"
}

GridFS 添加文件

现在我们使用 GridFS 的 put 命令来存储 mp3 文件。调用 MongoDB 安装目录下 bin 的 mongofiles.exe 工具。

打开命令提示符,进入到 MongoDB 的安装目录的 bin 目录中,找到 monfofiles.exe,并输入下面的代码:

>mongofiles.exe -d gridfs put song.mp3

GridFS 是存储文件的数据名称。如果不存在该数据库,MongoDB 会自动创建。 Song.mp3 是音频文件名。

使用以下命令来查看数据库中文件的文档:

>db.fs.files.find()

以上命令执行后返回以下文档数据:

{
   _id: ObjectId('534a811bf8b4aa4d33fdf94d'), 
   filename: "song.mp3", 
   chunkSize: 261120, 
   uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",
   length: 10401959 
}

我们可以看到 fs.chunks 集合中所有的区块,以下我们得到了文件的 _id 值,我们可以根据这个 _id 获取区块(chunk)的数据:

>db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})

以上实例中,查询但会了 40 个文档,意味着 mp3 文件被存储在 40 个区块中。

MongoDB 固定集合(Capped Collections)

MongoDB 固定集合(Capped Collections)是性能更出色且有固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,在插入的元素就会覆盖最初始的头部的元素!

创建固定集合

我们用过 createCollection 来创建一个固定集合,且 capped 选项设置为 true:

>db.createCollection("cappedLogCollection",{capped:true,size:10000})

还可以指定文档个数,加上max:1000属性:

>db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})

判断集合是否为固定集合:

>db.cappedLogCollection.isCapped()

如果需要将已存在的集合转换为固定集合可以使用以下命令:

>db.runCommand({"convertToCapped":"posts",size:10000})

以上代码将我们已存在的 posts 集合转换为固定集合。

固定集合查询

固定集合文档按照插入顺序存储的,默认情况下查询就是按照插入顺序返回的,也可以使用$natural 调整返回顺序。

>db.cappedLogCollection.find().sort({$natural:-1})

固定集合的功能特点

可以插入即更新,但更新不能超出 collection 的大小,否则更新失败,不允许删除,但是可以调用 drop()删除集合中的所有行,但是 drop 后需要显式的重建集合。

在 32 位 机子上一个 capped collection 的最大值约为 482.5M,64位 上只受系统文件大小的限制。

固定集合属性及用法

属性

  • 属性1:对固定集合进行插入速度极快
  • 属性2:按照插入顺序的查询输出速度极快
  • 属性3:能够在插入最新数据时,淘汰最早的数据

用法

  • 用法1:储存日志信息。
  • 用法2:缓存一些少量的文档。
db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})

size:是整个集合空间大小,单位为 KB
max:是集合文档个数上限,单位是 个

如果空间大小到达上限,则插入下一则文档时,会覆盖第一个文档;如果文档个数到达上限,永阳插入下一个文档时,会覆盖第一个文档。两个单数上限判断取的是 与 的逻辑。

MongoDB 自动增长

MongoDB 没有像 SQL 一样有自动增长的功能,MongoDB的 _id 是系统自动生成的 12 字节唯一标识。

但在某些情况下,我们可能需要实现 ObjectId 自动增长的功能。

由于 MongoDB 没有实现这个功能,我们可以通过编程的方式来实现,以下我们将在 counters 集合中实现 _id 字段自动增长。

使用 counters 集合

考虑以下 products 文档。我们希望 _id 字段实现从 1,2,3,4到n的自动增长功能。

{
  "_id":1,
  "product_name": "Apple iPhone",
  "category": "mobiles"
}

为此,创建 counters 集合,序列字段值可以实现自动增长:

>db.createCollection("counters")

现在我们向 counters 集合中插入以下文档,使用 productid 作为 key:

{
  "_id":"productid",
  "sequence_value": 0
}

sequence_value 字段是序列通过自动增长的一个值。

使用以下命令插入 counters 集合的序列文档中:

>db.counters.insert({_id:"productid",sequence_value:0})

创建 Javascript 函数

现在,我们创建函数 getNextSequenceValue 来作为序列名的输入,指定的序列会自动增长 1,并返回最新序列值。在本文的实例中序列名为 poeductid 。

>function getNextSequenceValue(sequenceName){
   var sequenceDocument = db.counters.findAndModify(
      {
         query:{_id: sequenceName },
         update: {$inc:{sequence_value:1}},
         "new":true
      });
   return sequenceDocument.sequence_value;
}

使用 Javascript 函数

接下来我们将使用 getNextSequenceValue 函数创建一个新的文档,并设置文档_id 自动为返回的序列值:

>db.products.insert({
   "_id":getNextSequenceValue("productid"),
   "product_name":"Apple iPhone",
   "category":"mobiles"})

>db.products.insert({
   "_id":getNextSequenceValue("productid"),
   "product_name":"Samsung S3",
   "category":"mobiles"})

就如你所看到的,我们使用 getNextSequenceValue 函数来设置_id 字段。

为了验证函数是否有效,我们可以使用以下命令读取文档:

>db.products.find()

以上命令将返回以下结果。我们发现 _id 字段是自动增长的:

{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}

{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }

释放磁盘空间

MongoDB 不会释放已经占用的硬盘空间。即使删除 dn 中的集合也不会释放磁盘空间。 同样,如果使用 GridFS 存储文件,从 GridFS 存储中删除无用的垃圾文件, MongoDB 依然不会释放磁盘空间的。这会造成磁盘一直在消耗,而无法回收利用的问题。

以下两种方式可以释放磁盘空间

修复数据库命令

可以通过修复数据库来回收磁盘空间,即在mongo shell中运行db.repairDatabase()命令或者db.runCommand({ repairDatabase: 1 })命令。(此命令执行比较慢)。

使用通过修复数据库方法回收磁盘时需要注意,但修复磁盘的剩余空间必须大于等于存储数据集占用空间家伙加上 2G ,否则无法完成修复。

因此使用 GridFS 大量存储文件不许提前考虑设计磁盘回收方案,以解决 mongoDB 磁盘回收问题。

使用 dump & restore 方式

即先删除 MongoDB 数据库中需要清除的数据,然后使用 mongodump 备份数据库。备份完成后,删除 MongoDB 的数据库,使用 Mongorestore 工具恢复备份数据到数据库。

当使用 db.repairDatabase()命令没有足够的磁盘剩余空间时,可以采用 dump & restore 方式回收磁盘空间。如果 MongoDB 是副本集模式, dump & restore 方式可以做到对外持续服务,在不影响 MongoDB 正常使用下回收磁盘资源。

你可能感兴趣的:(NoSQL,MongoDB)