GridFS
概述
在本指南中,您可以了解如何使用GridFS在MongoDB中存储和检索大文件。GridFS是一种规范,描述了在存储期间如何将文件分割成块,在检索期间如何重新组装它们。Rust驱动程序的GridFS实现管理文件存储的操作和组织。
如果您文件的尺寸超过16MB的BSON文档大小限制,请使用GridFS。GridFS还可以帮助您在不将整个文件加载到内存的情况下访问文件。有关GridFS是否适合您的用例的更详细信息,请参阅服务器手册中的GridFS页面。GridFS页面。
要了解更多关于GridFS的信息,请参阅本指南的以下部分
GridFS工作原理
GridFS以存储桶的形式组织文件,存储桶是一组包含文件块和描述性信息的MongoDB集合。存储桶包含以下集合,命名方式遵循GridFS规范中定义的约定
chunks
,存储二进制文件块files
,存储文件元数据
当您创建一个新的GridFS存储桶时,Rust驱动程序执行以下操作
创建以默认存储桶名称
fs
为前缀的chunks
和files
集合,除非您指定不同的名称在每个集合上创建索引,以确保高效检索文件和相关元数据
您可以通过遵循本页的引用GridFS存储桶部分中的步骤来创建对GridFS存储桶的引用。但是,直到第一次写入操作之前,驱动程序不会创建新的GridFS存储桶及其索引。有关GridFS索引的更多信息,请参阅服务器手册中的GridFS索引页面。
当将文件存储在GridFS桶中时,Rust驱动程序会创建以下文档
在
files
集合中创建一个文档,用于存储唯一的文件ID、文件名和其他文件元数据在
chunks
集合中创建一个或多个文档,用于存储文件内容,驱动程序将其拆分成更小的部分
以下图表描述了GridFS在上传到桶时如何拆分文件

在检索文件时,GridFS从指定桶中的files
集合中检索元数据,并使用该信息从chunks
集合中的文档重新构建文件。您可以读取文件到内存或将它输出到流中。
引用GridFS桶
在将文件存储到GridFS桶之前,创建一个桶引用或获取现有桶的引用。
以下示例在数据库实例上调用gridfs_bucket()
方法,它创建对新或现有GridFS桶的引用
let bucket = my_db.gridfs_bucket(None);
您可以通过设置GridFsBucketOptions
结构体的bucket_name
字段来指定自定义桶名称。
注意
结构体实例化
Rust驱动程序为某些结构类型实现了Builder设计模式,包括GridFsBucketOptions
。您可以使用builder()
方法通过链接选项构建方法来构建每种类型的实例。
以下表格描述了您可以使用的方法来设置GridFsBucketOptions
字段
方法 | 可能值 | 描述 |
---|---|---|
bucket_name() | 任何 String 值 | 指定桶名称,默认设置为 fs |
chunk_size_bytes() | 任何 u32 值 | 指定用于将文件拆分成块的字块大小,默认为255 KB |
write_concern() | WriteConcern::w() ,WriteConcern::w_timeout() ,WriteConcern::journal() ,WriteConcern::majority() | 指定桶的写关注,默认设置为数据库的写关注 |
read_concern() | ReadConcern::local() 、ReadConcern::majority() 、ReadConcern::linearizable() 、ReadConcern::available() 、ReadConcern::snapshot() | 指定桶的读关注,默认设置为数据库的读关注 |
selection_criteria() | SelectionCriteria::ReadPreference ,SelectionCriteria::Predicate | 指定哪些服务器适用于桶操作,该操作设置为数据库的选择条件,默认为 默认条件 |
以下示例指定了GridFsBucketOptions
实例中的选项,以配置自定义桶名称和写入操作的五秒超时限制
let wc = WriteConcern::builder().w_timeout(Duration::new(5, 0)).build(); let opts = GridFsBucketOptions::builder() .bucket_name("my_bucket".to_string()) .write_concern(wc) .build(); let bucket_with_opts = my_db.gridfs_bucket(opts);
上传文件
您可以通过打开上传流并将文件写入流来将文件上传到GridFS桶。在您的桶实例上调用open_upload_stream()
方法以打开流。此方法返回一个GridFsUploadStream
实例,您可以将文件内容写入其中。要将文件内容上传到GridFsUploadStream
,请调用write_all()
方法并将您的文件字节作为参数传递。
提示
导入所需的模块
GridFsUploadStream
结构实现了futures_io::AsyncWrite
特性。要使用AsyncWrite
写入方法,如write_all()
,将AsyncWriteExt
模块导入您的应用程序文件,并使用以下use声明
use futures_util::io::AsyncWriteExt;
以下示例使用上传流将名为"example.txt"
的文件上传到GridFS桶
let bucket = my_db.gridfs_bucket(None); let file_bytes = fs::read("example.txt").await?; let mut upload_stream = bucket.open_upload_stream("example").await?; upload_stream.write_all(&file_bytes[..]).await?; println!("Document uploaded with ID: {}", upload_stream.id()); upload_stream.close().await?;
下载文件
您可以通过打开下载流从GridFS桶中读取文件。在您的桶实例上调用open_download_stream()
方法,指定所需文件的_id
值作为参数。此方法返回一个GridFsDownloadStream
实例,您可以通过它访问文件。要从GridFsDownloadStream
读取文件,请调用read_to_end()
方法并将向量作为参数传递。
提示
导入所需的模块
结构体GridFsDownloadStream
实现了futures_io::AsyncRead
特质。要使用AsyncRead
的读取方法,如read_to_end()
,请在您的应用程序文件中导入AsyncReadExt
模块,使用以下use声明
use futures_util::io::AsyncReadExt;
以下示例使用下载流从GridFS存储桶中下载一个值为3289
的文件
let bucket = my_db.gridfs_bucket(None); let id = ObjectId::from_str("3289").expect("Could not convert to ObjectId"); let mut buf = Vec::new(); let mut download_stream = bucket.open_download_stream(Bson::ObjectId(id)).await?; let result = download_stream.read_to_end(&mut buf).await?; println!("{:?}", result);
注意
GridFS流式API不能加载部分块。当下载流需要从MongoDB中拉取一个块时,它会将整个块拉入内存。255 KB的默认块大小通常足够,但您可以减小块大小以减少内存开销。
检索文件信息
您可以从GridFS存储桶的files
集合中检索文件信息。每个文件都存储为FilesCollectionDocument
类型的实例,该类型包括以下字段,代表文件信息
_id
:文件IDlength
:文件大小chunk_size_bytes
:文件块的大小upload_date
:文件的上传日期和时间filename
:文件名metadata
:存储用户指定元数据的文档
在GridFS存储桶实例上调用find()
方法以从存储桶中检索文件。该方法返回一个游标实例,您可以通过该实例访问结果。
以下示例检索并打印GridFS存储桶中每个文件的大小
let bucket = my_db.gridfs_bucket(None); let filter = doc! {}; let mut cursor = bucket.find(filter).await?; while let Some(result) = cursor.try_next().await? { println!("File length: {}\n", result.length); };
重命名文件
您可以通过在bucket实例上调用rename()
方法来更新bucket中GridFS文件的名字。将目标文件的_id
值和新文件名作为参数传递给rename()
方法。
注意
rename()
方法一次只能更新一个文件的名字。要重命名多个文件,从bucket中检索匹配文件名的文件列表,从您想要重命名的文件中提取_id
字段,并将每个值单独调用rename()
方法。
以下示例将包含_id
值为3289
的文件的filename
字段更新为"new_file_name"
。
let bucket = my_db.gridfs_bucket(None); let id = ObjectId::from_str("3289").expect("Could not convert to ObjectId"); let new_name = "new_file_name"; bucket.rename(Bson::ObjectId(id), new_name).await?;
删除文件
您可以使用delete()
方法从bucket中删除文件。要删除文件,请在bucket实例上调用delete()
并传递文件的_id
值作为参数。
注意
delete()
方法一次只能删除一个文件。要删除多个文件,从bucket中检索文件,从您想要删除的文件中提取_id
字段,并将每个_id
值单独调用delete()
方法。
以下示例删除了_id
字段值为3289
的文件。
let bucket = my_db.gridfs_bucket(None); let id = ObjectId::from_str("3289").expect("Could not convert to ObjectId"); bucket.delete(Bson::ObjectId(id)).await?;
删除 GridFS 存储桶
您可以使用 drop()
方法来删除存储桶,这将删除存储桶的 files
和 chunks
集合。要删除存储桶,请在其实例上调用 drop()
。
以下示例演示了如何删除 GridFS 存储桶
let bucket = my_db.gridfs_bucket(None); bucket.drop().await?;
更多信息
API 文档
要了解更多关于本指南中提到的任何方法或类型的信息,请参阅以下 API 文档