日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一文说通Dotnet操作MongoDB GridFS

發布時間:2023/12/4 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文说通Dotnet操作MongoDB GridFS 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

補個技術債。

?

這個主題一直在列表中,今天把它補上。還有一個原因,就是網上能查到的代碼,大多已經過期了。今天寫的,是按最新的SDK做的例子。

?

一、MongoDB GridFS

先說說 GridFS。

MongoDB 是用 Bson 來存儲數據的,每一行數據,稱為 Document。每個 Document,大小有個上限,是16M,也就是說,結構化數據量大的空間占用是16M。注意,這個16M不是簡單的內容總和,因為 Bson 對于字段名和類型有一定的特殊處理,實際存儲的內容在計算上或多或少會有些變化,真正限制的是存儲 Bson 的16M。

對于超過16M的數據,比方一個圖片文件,MongoDB 也提供了一種存儲方式,就是 GridFS。

不同于常規的結構數據存儲,MongoDB 在存儲 GridFS 數據時,用了兩個集合(Collection):fs.files 和 fs.chunks。files 集合用來存儲文件的相關信息,chunks 集合用來存儲真正的文件塊。

在SDK早期,這兩個集合可以獨立操作(因為這兩個文件本身也是可操作的集合)。但實際應用中,這帶來了相當程度的混亂。因此,在SDK 2.0以后,加入了一個桶(Bucket)的概念。從此,操作GridFS的流程變成了:開發者對「桶」進行操作,而「桶」在系統內部進行對兩個集合的操作。

這就是上面說的過期代碼的問題。

?

桶(Bucket)在MongoDB 中是個概念,對應著兩個集合 files 和 chunks。桶的默認名稱是 fs,對應的兩個集合是 fs.files 和 fs.chunks。我們也可以給桶命名,例如 Test,則對應的集合會是 Test.files 和 Test.chunks。

二、操作GridFS

在操作GridFS時,我們會直接對桶(Bucket)操作。桶是建立在數據庫 Database 上的。

1. 前置操作

要使用GridFS,我們需要引入一個庫:

%?dotnet?add?package?MongoDB.Driver.GridFS

這個庫是MongoDB官方的Dotnet庫。

引入這個庫時,系統會加入以下四個庫:

  • MongoDB.Bson

  • MongoDB.Driver

  • MongoDB.Driver.Core

  • MongoDB.Driver.GridFS

熟悉MongoDB開發的會清楚,前三個是結構化操作需要引入的庫。而第四個,就是 GridFS 操作的庫。

2. 打開Bucket

其實我更愿意叫連接。就是連接到一個桶的意思。

var?client?=?new?MongoClient(connection_string);; var?database?=?client.GetDatabase("TestDatabase"); var?bucket?=?new?GridFSBucket(database);

三行代碼,就連接到了一個Bucket。

如果需要連接到一個指定名稱的Bucket,可以用下面的代碼:

var?bucket?=?new?GridFSBucket(database,?new?GridFSBucketOptions {BucketName?=?"Test", });

3. 上傳文件

上傳文件,Bucket提供了兩個方法

  • UploadFromBytes

  • UploadFromStream

以及對應的異步方法:

  • UploadFromBytesAsync

  • UploadFromStreamAsync

此外,還提供了一組流式操作方法:

  • OpenUploadStream

  • OpenUploadStreamAsync

?

這其實就是一個簡單的IO操作:

using?(var?fs?=?new?FileStream(file_path,?FileMode.Open)) {var?id?=?await?bucket.UploadFromStreamAsync(file_name,?fs); }

成功后會返回ObjectId。

方法里的file_name,對應保存到files里的文件名filename。其實它是一個標識,用來讓你查找文件用的。這個標識對應一個索引,是 { "filename" : 1, "uploadDate" : 1 }。對于相同的文件名,MongoDB視為同一個文件的多個版本,并通過uploadDate來區分版本。

?

我們來看一下保存后的數據:

Test.files

{?"_id"?:?ObjectId("60583228d37a5aec3c011557"),?"length"?:?73268,?"chunkSize"?:?261120,?"uploadDate"?:?ISODate("2021-03-22T13:59:05.278+0800"),?"md5"?:?"f2fe3c4e2828082ad9e82a11fabe6dd0",?"filename"?:?"test.jpg" }

Test.chunks

{?"_id"?:?ObjectId("60583229d37a5aec3c011558"),?"files_id"?:?ObjectId("60583228d37a5aec3c011557"),?"n"?:?0,?"data"?:?BinData(0,?"/9j/...") }

這是對應的兩個集合里的一條數據。上面說的返回的ObjectId,是files里的_id值。

?

實際應用時,files集合里記錄的文件信息有點少,我們需要加一些我們自己想存入的信息。這時候,可以這么寫:

var?options?=?new?GridFSUploadOptions {Metadata?=?new?BsonDocument{{?"width",?"1024"?},{?"height",?"768"?}} }; var?id?=?await?bucket.UploadFromStreamAsync(file_name,?fs,?options);

我們通過Metadata,把我們自己的數據也存到了files表里。

再看一下數據:

{?"_id"?:?ObjectId("60583228d37a5aec3c011557"),?"length"?:?73268,?"chunkSize"?:?261120,?"uploadDate"?:?ISODate("2021-03-22T13:59:05.278+0800"),?"md5"?:?"f2fe3c4e2828082ad9e82a11fabe6dd0",?"filename"?:?"test.jpg",?"metadata"?:?{"width"?:?"1024",?"height"?:?"768"} }

4. 下載文件

同上傳類似,一組直接方法:

  • DownloadAsBytes

  • DownloadAsBytesAsync

  • DownloadToStream

  • DownloadToStreamAsync

  • DownloadAsBytesByName

  • DownloadAsBytesByNameAsync

  • DownloadToStreamByName

  • DownloadToStreamByNameAsync

以及一組流式方法:

  • OpenDownloadStream

  • OpenDownloadStreamAsync

  • OpenDownloadStreamByName

  • OpenDownloadStreamByNameAsync

內容上跟上傳相似,多了一類用名稱查找的方法。

?

看個簡單的例子:

using?(var?fs?=?new?FileStream(save_file_name,?FileMode.Create)) {await?bucket.DownloadToStreamAsync(new?ObjectId("60583228d37a5aec3c011557")),?fs); }

給出ID,就是上面保存時返回的ID值,就可以下載文件到本地。

如果需要根據文件名下載,是這樣的:

using?(var?fs?=?new?FileStream(save_file_name,?FileMode.Create)) {await?bucket.DownloadToStreamByNameAsync("test.jpg",?fs); }

這樣,我們就下載到文件的最新版本了。如果想獲取文件的其它版本,可以加一個參數:

using?(var?fs?=?new?FileStream(save_file_name,?FileMode.Create)) {await?bucket.DownloadToStreamByNameAsync("test.jpg",?fs,?new?GridFSDownloadByNameOptions{Revision?=?0}); }

5. 查找文件

查找文件跟結構化數據的查詢沒有區別,唯一的是引用的定義不同。

var?filter?=?Builders<GridFSFileInfo>.Filter.Eq(x?=>?x.Filename,?"test.jpg");s var?sort?=?Builders<GridFSFileInfo>.Sort.Descending(x?=>?x.UploadDateTime); var?options?=?new?GridFSFindOptions {Limit?=?1,Sort?=?sort }; using?(var?cursor?=?bucket.Find(filter,?options)) {var?fileInfo?=?cursor.ToList().FirstOrDefault(); }

這個不詳細說了,一看就明白。

6. 刪除文件

也很簡單,根據ID直接刪。

刪除一個文件:

bucket.Delete(new?ObjectId("60583228d37a5aec3c011557"));

await?bucket.DeleteAsync(new?ObjectId("60583228d37a5aec3c011557"));

7. 刪除Bucket

這也是一個方法:

bucket.Drop();

await?bucket.DropAsync();

這是一次性刪除存在Bucket中的所有數據的最快方法。

三、分片

要想用好MongoDB集群,就得玩好分片。放到MongoDB集群里的GridFS,也需要分片。

不過,GridFS分片很簡單。

GridFS有兩個集合,files 和 chunks。兩個集合數據大小完全不一樣。

files 集合只包含元數據,數據占用空間不大。如果沒有特殊原因,可以不分片。如果一定要分片,用_id做片鍵就好,或者用自己存儲的信息字段,也可以。

chunks 包含文件塊,數據占用空間很大,需要分片。分片時,可以用 { files_id : 1, n : 1} 做片鍵,也可以就直接用 { files_id : 1 } 做片鍵。對于MongoDB 4.0及以上的版本,還可以用 { files_id : "hashed", n : 1 } 來做片鍵。

?

這就是今天全部的內容了。

多說兩句:我發現很多人對MongoDB有一種莫名的抗拒,只是因為MongoDB不提供大家熟悉的SQL。其實,SQL也是一種應用語言。MongoDB雖然不使用SQL,但他的寫法,也是一種很簡單的語言結構,不用特別學習的。而且,MongoDB給我的最大驚喜是他的安裝部署。MongoDB做成了一個綠色軟件。一個服務器就一個程序,程序運行,數據庫就起來了。做個集群,也只是一些簡單的配置。加個帳號密碼,就相當的安全了。這是多么爽的事啊?

喜歡就來個三連,讓更多人因你而受益

總結

以上是生活随笔為你收集整理的一文说通Dotnet操作MongoDB GridFS的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。