首页 > 其他分享 >GridFS

GridFS

时间:2024-09-22 19:01:26浏览次数:1  
标签:files 文件 存储 GridFS 集合 id

 

1.概述

如果文件大小超过 16 MB 的 BSON 文档大小限制,可以使用 GridFS来存储和检索。GridFS 不将文件存储在一个文档中,而是大型数据进行分块处理,然后将这些切分后的小文档保存在数据库中。

 

2.GridFS 的工作原理

GridFS 在存储桶中组织文件,存储桶是一组包含文件块和描述性信息的 MongoDB 集合。存储桶包含以下集合,使用 GridFS 规范中定义的约定命名:

  • chunks 集合存储二进制文件块。
  • files 集合存储文件元数据。

创建新的 GridFS 桶时,驱动程序会创建 chunksfiles 集合,并以默认桶名称 fs 作为前缀,除非用户显式指定其他名称。驱动程序还会在每个集合上创建索引,以确保有效检索文件和相关元数据。如果 GridFS 桶尚不存在,驱动程序仅在第一次写入操作时创建该桶。仅当索引不存在且桶为空时,驱动程序才会创建索引。

使用 GridFS 存储文件时,驱动程序会将文件拆分成小块,每个块由 chunks 集合中的单个文档表示。它还在 files 集合中创建一个文档,其中包含唯一的文件 ID、文件名和其他文件元数据。可以从内存或数据流上传文件。下图描述了 GridFS 在将文件上传到存储桶时如何分割文件:

在检索文件时,GridFS 从指定存储桶上的 files 集合中获取元数据,并使用该信息通过 chunks 集合中的文档重建文件。用户可以将文件读取到内存中,或者将其输出到流。

2.1GridFS集合

GridFS将文件存储到两个集合中:chunks和files。GridFS将集合放到一个桶中并以桶名字作为前缀,默认的桶名是fs。因此两个集合是:fs.files和fs.chunks。

支持自定义桶的名字,单个数据库中可以创建多个桶。

2.2集合fs.files

{
  "_id" : <ObjectId>,      #文档的标识符,具有唯一性
  "length" : <num>,        #文档的长度,单位是bytes
  "chunkSize" : <num>,     #块大小,单位是bytes
  "uploadDate" : <timestamp>,#上传的时间
  "md5" : <hash>,            #md校验和,已经被取消
  "filename" : <string>,     #人可读的文件文件名,可选项
  "contentType" : <string>,
  "aliases" : <string array>,
  "metadata" : <any>,
}

2.3集合fs.chunks

集合中的每个文档表示文件的一个块。文档格式如下:

{
  "_id" : <ObjectId>,    #块标识符,具有唯一性
  "files_id" : <ObjectId>,#文件的id,对应fs.files中的集合
  "n" : <num>,            #块的序列号
  "data" : <binary>       #bson格式的数据
}

2.4GridFS索引

GridFS 在每个块和文件集合上使用索引,以提高效率。为方便起见,符合 GridFS 规范的驱动程序会自动创建这些索引。你也可以根据应用程序的需要创建其他索引。

chunks 索引

GridFS 使用 files_id 和 n 字段对 chunks 集合建立唯一的组合索引。这样就能高效检索数据块,如下例所示:

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

符合 GridFS 规范的驱动程序会在读写操作之前自动确保该索引存在。如果该索引不存在,可以执行以下操作,使用 mongosh 创建该索引:

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

files索引

GridFS 使用文件名和上传日期字段为files集合创建索引。如本例所示,通过该索引可以高效地检索文件:

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

符合 GridFS 规范的驱动程序会在读写操作之前自动确保该索引存在。如果该索引不存在,可以执行以下操作,使用 mongosh 创建该索引:

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

 

3.分片 GridFS

有两个集合需要考虑--files和chunks。

3.1chunks集合

要对 chunks 集合进行分片,可以使用 { files_id : 1, n : 1 } 或 { files_id : 1 } 作为分片键索引。

 

对于不运行 filemd5 来验证上传是否成功的 MongoDB 驱动程序,可以使用哈希分片来处理chunks集合。

 

如果 MongoDB 驱动程序运行 filemd5,则不能使用哈希分片。

3.2files集合

文件集很小,只包含元数据。GridFS 所需的键都不适合在分片环境中均匀分布。如果不对files集合进行分片,所有文件元数据文件都可以保存在主分片上。

 

如果必须对files集合进行分片,可以使用 _id 字段,也可以与应用程序字段结合使用。

 

4.何时使用 GridFS

在 MongoDB 中,使用 GridFS 来存储大于 16 MB 的文件。

 

某些情况下,在 MongoDB 数据库中存储大文件可能比在系统级文件系统中存储更有效:

·如果文件系统限制目录中的文件数量,可以使用 GridFS 来存储所需的文件。

·如果希望访问大文件中的部分信息,而无需将整个文件加载到内存中,则可以使用 GridFS 来调用文件的部分内容,而无需将整个文件读入内存。

·当想保持文件和元数据自动同步,并在多个系统和设施间部署时,可以使用 GridFS。在使用地理分布复制集时,MongoDB 可以将文件及其元数据自动分发到多个 mongod 实例和设施。

 

如果需要原子式更新整个文件的内容,请不要使用 GridFS。作为替代方案,你可以为每个文件存储多个版本,并在元数据中指定文件的当前版本。上传新版本的文件后,可以在原子更新中更新表示 “最新 ”状态的元数据字段,之后再根据需要删除以前的版本。

 

此外,如果文件都小于 16 MB BSON 文档大小限制,可以考虑将每个文件存储在单个文档中,而不是使用 GridFS。可以使用 BinData 数据类型来存储二进制数据。

 

5.使用GridFS

要使用GridFS,有两种方式:

·使用mongodb驱动器

·使用mongofiles命令行工具

5.1创建 GridFS 存储桶

创建一个存储桶或获取对现有存储桶的引用,以开始从 GridFS 存储或检索文件。创建一个 GridFSBucket 实例,并将数据库作为参数传递。然后,就可以使用 GridFSBucket 实例对存储桶中的文件调用读取和写入操作:

const db = client.db(dbName);
const bucket = new mongodb.GridFSBucket(db);

将存储桶名称作为第二个参数传递给 create() 方法,以创建或引用具有默认名称 fs 之外的自定义名称的存储桶,如以下示例所示:

const bucket = new mongodb.GridFSBucket(db, { bucketName: 'myCustomBucket' });

5.2上传文件

使用 GridFSBucket 中的 openUploadStream() 方法为指定文件名创建上传流。可以使用 pipe() 方法将 Node.js 读取流连接到上传流。使用 openUploadStream() 方法可以指定配置信息,如文件数据块大小和其他作为元数据存储的字段/值对。

以下示例展示了如何将由变量 fs 表示的 Node.js 读取流通过管道传递给 GridFSBucket 实例的 openUploadStream() 方法:

fs.createReadStream('./myFile').
     pipe(bucket.openUploadStream('myFile', {
         chunkSizeBytes: 1048576,
         metadata: { field: 'myField', value: 'myValue' }
     }));

5.3检索文件信息

元数据包含所引用文件的相关信息,包括:

  • 文件的 _id
  • 文件的名称
  • 文件的长度/大小
  • 上传日期和时间
  • 可以在其中存储任何其他信息的 metadata 文档

GridFSBucket 实例上调用 find() 方法,以便从 GridFS 存储桶中检索文件。该方法会返回一个 FindCursor 实例,可以从该实列访问结果。

以下代码示例向你展示如何从 GridFS 存储桶中的所有文件中检索和打印文件元数据。在从 FindCursor 可迭代表中遍历检索结果的各种方法中,以下示例使用 for await...of 事务语法来显示结果:

const cursor = bucket.find({});
for await (const doc of cursor) {
   console.log(doc);
}

find() 方法可接受各种查询说明,可与 sort()limit()project() 等其他方法结合使用。

5.4下载文件

可以使用 GridFSBucket 中的 openDownloadStreamByName() 方法创建下载流,从 MongoDB 数据库下载文件。

下面的示例展示了如何将存储在 filename 字段中的文件名引用的文件下载到工作目录中:

bucket.openDownloadStreamByName('myFile').
     pipe(fs.createWriteStream('./outputFile'));

注意:

如果存在多个具有相同 filename 值的文档,GridFS 将流式传输具有给定名称(由 uploadDate 字段决定)的最新文件。

或者可以使用 openDownloadStream() 方法将文件的 _id 字段作为参数:

bucket.openDownloadStream(ObjectId("60edece5e06275bf0463aaf3")).
     pipe(fs.createWriteStream('./outputFile'));

注意:

GridFS 流 API 无法加载块的部分数据。当下载流需要从 MongoDB 拉取一个数据块,它会将整个数据块拉入内存。255 KB 默认数据段大小通常足够。

5.5重命名文件

使用 rename() 方法更新存储桶中 GridFS 文件的名称。必须用文件的 _id 字段而不是文件名来指定要重命名的文件。

注意:

rename() 方法每次仅支持更新一个文件的名称。要重命名多个文件,请从存储桶中检索与文件名匹配的文件列表,从要重命名的文件中提取 _id 字段(Field),然后将每个值分别传递到 rename() 方法。

以下示例显示如何通过引用文档的 _id 字段(Field)将 filename 字段(Field)更新为“newFileName”:

bucket.rename(ObjectId("60edece5e06275bf0463aaf3"), "newFileName");

5.6删除文件

使用 delete() 方法以从存储桶中删除文件。必须用文件的 _id 字段而不是文件名来指定该文件。

注意:

delete() 方法一次只支持删除一个文件。要删除多个文件,请从存储桶中检索文件,提取要删除的文件中的 _id 字段,将每个值分别传递给 delete() 方法。

下面的示例展示了如何通过引用文件的 _id 字段来删除文件:

bucket.delete(ObjectId("60edece5e06275bf0463aaf3"));

5.7删除 GridFS 存储桶

使用 drop() 方法删除存储桶的 fileschunks 集合,从而有效删除存储桶。以下代码示例展示了如何删除 GridFS 存储桶:

bucket.drop();

 

6.GridFS 的局限性

事实上,没有放之四海而皆准的解决方案,MongoDB GridFS 也不例外。因此,请记住这些限制:

·从数据库中以多个块的形式持续提供大文件确实会影响工作集(一个 16MB 的文件会被检索为 65 个分块,每个分块 255KB),尤其是在处理千兆字节或万兆字节数据的情况下。

(针对这一点可以考虑使用专门的实例来提供GridFS功能、并增加块的默认大小)

·从数据库提供文件比从文件系统提供文件要慢一些。

·GridFS 本身并不提供原子更新整个文件的方法。因此,如果系统经常更新整个文件,就不要使用 GridFS 或使用下面讨论的变通方法。

(针对这一点可以考虑引入版本控制的思想,不过效果可能并不理想)

 

标签:files,文件,存储,GridFS,集合,id
From: https://www.cnblogs.com/abclife/p/18425288

相关文章

  • mongo GridFSBucket
    1、描述:mongo  单机使用 GridFSBucket2、pox中添加jar<dependency><groupId>org.mongodb</groupId><artifactId>mongo-java-driver</artifactId><version>3.12.9</version></dependency>3、module中使用,直接上代码 3.1......
  • GridFS上传&下载文件
     首先我们先说上传文件到GridFs;上传文件到GridFs上相对比较简单,只需要GridFsTemplate的store方法;    1.上传文件        如果文件为String类型则我们需要将其转化为inputstream的流对象,然后在调用store方法,如果需要返回字符串类型则可以使用tostring方法;InputStre......
  • 无涯教程-MongoDB - GridFS
    GridFS是MongoDB规范,用于存储和检索大文件,例如图像,音频文件,视频文件等,它是一种文件系统,用于存储文件,但其数据存储在MongoDB集合中。GridFS能够存储甚至超过其文档大小限制16MB的文件。GridFS将文件分为多个块,并将每个数据块存储在单独的文档中,每个文件的最大大小为255k。默......
  • springboot 整合 gridfs 、webUploader实现大文件分块上传、断点续传、秒传
    主要的pom.xml:<dependency>      <groupId>mysql</groupId>      <artifactId>mysql-connector-java</artifactId>    </dependency><!--mongodb-->    <dependency>      <groupId>org.spri......
  • 使用 MongoDB 的兄弟,有没有采用 GridFS 做分布式文件系统的?
    修改写补充说明郭理靖,京东开放平台邓涛、Kenny、李波等人赞同压力以及数据量比较大的业务不推荐使用MongoGridFS。MongoGridFS在高并发(每秒写入10M,持续半小时到一个小时)的情况下secondary会无法catchupwithprimary。MongoGridFS不是为分......
  • pythongridFS
    PythonGridFS:用于存储和检索大文件的Python库![gridfs_logo](简介PythonGridFS是一个基于Python的库,用于在MongoDB数据库中存储和检索大文件。MongoDB是一个流行的文档型NoSQL数据库,它提供了GridFS作为一个标准的文件系统存储解决方案。GridFS可以处理超出MongoDB文档大小限制......
  • 解决MongoDB之Gridfs的具体操作步骤
    MongoDB之GridFS什么是GridFSGridFS是MongoDB的一种存储文件的方式,它可以用于存储和检索大型文件。在传统的MongoDB中,适合存储的文件大小通常限制在16MB以内,而GridFS可以突破这个限制,支持存储非常大的文件。GridFS将大文件分割为小块,每个小块都被存储为一个MongoDB文档。同时,Gri......
  • nginx-gridfs Benchmarking Raw Results
    RawDataSpreadsheetwithtestresults(ODFformat)Thesefollowinglinksshowtherawoutputfromthebenchmarkingutilities.GridFSOverNetworkThistestscenarioshowsperformanceforHTTPrequestsoveragigabitEthernetLANconnection.MongoDBand......
  • MongoDB C++ gridfs worked example
    使用libmongoc,参考:http://mongoc.org/libmongoc/current/mongoc_gridfs_t.html#include<mongoc.h>#include<stdio.h>#include<stdlib.h>#include<fcntl.h>classMongoGridFS{public:MongoGridFS(constchar*db);~MongoGridFS();......
  • MongoDB GridFS最佳应用概述
    《MongoDBGridFS最佳应用概述》作者:chszs,转载需注明。GridFS是MongoDB数据库之上的一个简单文件系统抽象。如果你熟悉AmazonS3的话,那么GridFS与之相似。为什么像MongoDB这......