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 的 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)是性能更出色且有固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,在插入的元素就会覆盖最初始的头部的元素!
我们用过 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位 上只受系统文件大小的限制。
属性
用法
db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})
size:是整个集合空间大小,单位为 KB
max:是集合文档个数上限,单位是 个
如果空间大小到达上限,则插入下一则文档时,会覆盖第一个文档;如果文档个数到达上限,永阳插入下一个文档时,会覆盖第一个文档。两个单数上限判断取的是 与 的逻辑。
MongoDB 没有像 SQL 一样有自动增长的功能,MongoDB的 _id 是系统自动生成的 12 字节唯一标识。
但在某些情况下,我们可能需要实现 ObjectId 自动增长的功能。
由于 MongoDB 没有实现这个功能,我们可以通过编程的方式来实现,以下我们将在 counters 集合中实现 _id 字段自动增长。
考虑以下 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})
现在,我们创建函数 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;
}
接下来我们将使用 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 磁盘回收问题。
即先删除 MongoDB 数据库中需要清除的数据,然后使用 mongodump 备份数据库。备份完成后,删除 MongoDB 的数据库,使用 Mongorestore 工具恢复备份数据到数据库。
当使用 db.repairDatabase()命令没有足够的磁盘剩余空间时,可以采用 dump & restore 方式回收磁盘空间。如果 MongoDB 是副本集模式, dump & restore 方式可以做到对外持续服务,在不影响 MongoDB 正常使用下回收磁盘资源。