mongoDB應(yīng)用篇-mongo高級應(yīng)用之TTL索引-文本索引與固定集合-GridFS存儲

上篇我們學(xué)習(xí)了MongoDB中的索引機(jī)制以及常見的索引管理,除此之外,MongoDB還支持一些針對特殊業(yè)務(wù)的集合或者索引,例如支持空間存儲索引,支持固定大小集合,支持搜索和TTL索引,除此之外,MongoDB還支持GridFS存儲,本篇我們就來學(xué)習(xí)一下這些高級應(yīng)用特性

固定大小集合

在MongoDB中的普通集合都是動態(tài)增長的,而且可以自動增長以容納更多的數(shù)據(jù)。MongoDB中還有另一種不同類型的集合,叫做固定集合,固定集合需要事先創(chuàng)建好,而且它的大小是固定的。這種集合我們可以看成是一個固定的環(huán),每一個數(shù)據(jù)都是環(huán)上的一部分。使用固定大小的集合也會引出一個新的思考,如果集合滿了,我們再次插入會如何?答案是最先插入的數(shù)據(jù)會被移除,可以理解為集合像環(huán)形一樣,每次都會插入都會換到下一個位置,當(dāng)集合存滿以后,集合的位置再次來到起點(diǎn)的位置,這個時候會把原來的數(shù)據(jù)溢出,新的文檔將會占據(jù)這個位置。

也因?yàn)楣潭系奶厥庑?,?dǎo)致和普通的集合有很大的不同,比如固定集合由于大小固定,因此使用的是固定空間,數(shù)據(jù)可以順序?qū)懭?,因此在磁盤上上的寫入速度非常快,除此之外,固定集合也不能被分片。

創(chuàng)建·固定集合

MongoDB中創(chuàng)建固定集合可以設(shè)置兩種大小,第一種就是設(shè)置集合內(nèi)存大小-即字節(jié)數(shù),例如我們創(chuàng)建一個限制10000字節(jié)大小的固定集合:

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

而另外一種,則是限制存入集合的文檔數(shù)量,如下:

db.createCollection("appedLogCollection2",{capped:true,size:10000,max:10})

其中max字段則指定了文檔的數(shù)量,可以使用這種方式,就限制了存入集合中的文檔永遠(yuǎn)只有最新的十條。需要注意的是,一旦創(chuàng)建了固定集合以后,其大小和數(shù)量限制都無法再去修改了,如果真的要改變,只能選擇刪除當(dāng)前集合,再去重新創(chuàng)建,因此在創(chuàng)建固定集合之前建議考慮清楚需要設(shè)置的限制大小,如果是同事設(shè)置了文檔數(shù)量以及集合大小的情況下,會按照優(yōu)先觸發(fā)的為主進(jìn)行限制,而不是需要等待兩個限制都觸發(fā)。

如果在開發(fā)過程中,需要將一個普通的集合轉(zhuǎn)換為固定集合,我們可以使用convertToCapped命令實(shí)現(xiàn),如下:

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

這里的convertToCapped指定的是需要轉(zhuǎn)換為固定集合的集合名稱,而當(dāng)前db下有哪些集合,我們可以通過show collections命令查看,但是需要注意的是,普通集合可以轉(zhuǎn)為固定集合,而固定集合則無法轉(zhuǎn)換回普通集合,因此在進(jìn)行集合轉(zhuǎn)換的時候,需要慎重考慮,除此之外,轉(zhuǎn)換固定集合有可能出現(xiàn)錯誤,例如原集合中本來就有1000字節(jié)以上的大小,但是轉(zhuǎn)換為固定集合的時候指定了大小小于1000字節(jié),或者該集合已經(jīng)被轉(zhuǎn)換為固定集合了以后,我們選擇再次進(jìn)行轉(zhuǎn)換,就會轉(zhuǎn)換失敗,因此為了防止轉(zhuǎn)換失敗,我們可以在轉(zhuǎn)換之前先去判斷一下該集合是否為固定集合,如下:

db.appedLogCollection.isCapped();//true

如果這里結(jié)果為true,則表示當(dāng)前集合已經(jīng)是固定集合,無需在進(jìn)行轉(zhuǎn)換了。

自然排序

對固定集合進(jìn)行一種特殊的排序,稱之為自然排序,而所謂自然排序返回的順序和文檔在磁盤上的順序是一致的。由于普通的集合來說,磁盤空間不固定,大小不固定,因此自然排序是沒有任何意義的,但是對于固定集合來說,本身在磁盤上就是固定的內(nèi)存,文檔是順序?qū)懭氲模虼俗x取出來的文檔就是按照從舊到新的方式排列的,如果我們需要從新到舊排序,將最新的數(shù)據(jù)放在最前面的話,可以使用固定集合的{"$natural" : -1}進(jìn)行排序:

db.appedLogCollection.find().sort({"$natural":1});//按照自然排序-從舊到新排序
db.appedLogCollection.find().sort({"$natural":-1});//自然排序反向-從最新到最舊

TTL索引

我們知道,對于集合,尤其是固定集合中的文檔何時覆蓋,我們對其控制的很有限,并且無法手動刪除部分?jǐn)?shù)據(jù),如果我們想要更加靈活的操作文檔,將文檔移除,可以選擇在插入文檔的時候,給每一個文檔設(shè)置一個TTL時間,即過期時間,到了這個時間以后,這個文檔就會默認(rèn)被刪除。

我們來給集合中創(chuàng)建一個ttl索引:

db.ttlCollection.ensureIndex({"create_time":1},{expireAfterSeconds:180})

其中expirAfterSeconds字段指定了過期時間為180s,即create_time字段的時間在180s以前的都會被認(rèn)為過期刪除,但是這里我們需要注意的一點(diǎn)是,想要設(shè)置TTL索引,必須滿足以下幾個條件:

1).TTL只能針對單個索引字段有效,即混合字段是無法設(shè)置TTL索引的

2).想要設(shè)置為TTL的索引字段,必須是date格式,例如我們這里插入一條數(shù)據(jù)為:

db.ttlCollection.insert({"code":"11","name":"dc","age":18,"create_time":new Date('Nov 12, 2020 16:08:00')})

除此之外,文檔是否過期的掃描,并不是實(shí)時的,在MongoDB中進(jìn)行刪除操作是獨(dú)立的線程執(zhí)行的,默認(rèn)60S會去掃描一次,即使掃描到了文檔過期,由于是獨(dú)立線程的原因,也不一定會立刻刪除成功,因此文檔的過期可能會出現(xiàn)延遲的情況

如果我們不想刪除經(jīng)常使用的文檔,可以考慮在每次使用文檔的時候,都將TTL索引的字段值進(jìn)行修改,改為當(dāng)前的時間,這樣就可以保證文檔一直在TTL范圍內(nèi)不被移除。同樣,也因?yàn)門TL默認(rèn)60S,因此我們不應(yīng)該依賴以秒為單位的時間保證索引的活躍狀態(tài)。當(dāng)然在創(chuàng)建完TTL索引以后,如果想要修改TTL的值,可以使用collMod選項(xiàng)來重置expirAfterSeconds的值,如下:

db.runCommand({collMod: 'ttlCollection', index: {keyPattern:{create_time:1}, expireAfterSeconds:800}})

這里的collMod字段指定的是需要修改的集合,keyPattern則是需要修改的TTL索引字段信息,修改完畢以后我們再次查看當(dāng)前集合的索引信息:

 db.ttlCollection.getIndexes();
 //輸出
 [
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "set.ttlCollection"
        },
        {
                "v" : 2,
                "key" : {
                        "create_time" : 1
                },
                "name" : "create_time_1",
                "ns" : "set.ttlCollection",
                "expireAfterSeconds" : NumberLong(800)
        }
]

可以清晰看到name為create_time_1的索引的expireAfterSeconds已經(jīng)變?yōu)榱?00

設(shè)置刪除時間

除了前面給某一個date字段設(shè)置到期的時間以外,我們有可能遇到以下場景,如需要清理在2020年11月13日之前的過期數(shù)據(jù),并且每隔一段時間都會更新具體過期的時間,而不是插入了多久以后算過期,這個時候我們設(shè)置ttl為正數(shù)已經(jīng)不合適了,但是我們依然可以利用TTL的特點(diǎn)來完成這個操作,如下:

//1.將集合每個文檔中添加一個clear_time字段指定刪除時間(并且保證每次插入的文檔都有一個clear_time字段)
db.getCollection("ttlCollection").update({},{"$set":{"clear_time":new Date("Nov 13, 2020 00:00:00")}});
//2.刪除原來的ttl,重新設(shè)置ttl時間為0,字段為clear_time
 db.ttlCollection.dropIndex("create_time_1");
  db.ttlCollection.ensureIndex({"clear_time":1},{expireAfterSeconds:0});

接著等待一段時間,再去查詢,發(fā)現(xiàn)之前插入的11月12日的數(shù)據(jù)已經(jīng)全部被刪除了

全文檢索

MonoDB從2.4版本開始,加入了一個特殊的索引類型,用于在文檔中搜索文本,雖然前面學(xué)過可以根據(jù)正則等來進(jìn)行搜索,但是在大文本中用正則搜索,會導(dǎo)致非常慢,并且很多場景下因?yàn)榧夹g(shù)受限無法進(jìn)行匹配搜索。但是使用全文索引不一樣,其內(nèi)部也內(nèi)置和支持了多種分詞機(jī)制。需要注意的是,創(chuàng)建全文檢索索引的成本要高于其他的普通索引,存入的字符串會被分解分詞后進(jìn)行保存,因此創(chuàng)建全文檢索的時候建議是在后臺創(chuàng)建或者離線創(chuàng)建,并且在寫入的時候因?yàn)椴鸱衷~組的原因,會比普通集合慢的多,如果做了分片的話,也會導(dǎo)致分片的遷移速度變慢,并且如果遷移到了其他分片,所有的文本還需要重新構(gòu)建索引,這樣可能會帶來一段時間的內(nèi)存和效率的開銷。

支持的語言

截止到4.0版本,mongodb的全文索引支持的全文索引的語言達(dá)到了15種,如下:

  • danish
  • dutch
  • english
  • finnish
  • french
  • german
  • hungarian
  • italian
  • norwegian
  • portuguese
  • romanian
  • russian
  • spanish
  • swedish
  • turkish

開啟全文索引

mongoDB在2.6版本及以后默認(rèn)是開啟全文索引的,不需要額外去手動開啟,如果是2.6以前的版本,可以使用setParameter命令完成全文索引的開啟:

db.adminCommand({setParameter:true,textSearchEnabled:true})
//或者在啟動mongod的時候指定
mongod --setParameter textSearchEnabled=true

開啟全文索引以后,我們來給一個集合中插入一些文檔數(shù)據(jù),需要注意的是這里的文本不建議包含中文,格式如下:

{
   "p_text": "enjoy the mongodb articles on Runoob",
   "tags": [
      "mongodb",
      "runoob"
   ]
}

接著我們可以給p_text字段設(shè)置類型為text的索引,即文本索引:

db.postText.ensureIndex({p_text:"text"})

使用全文索引

如果我們想要針對加了全文索引的字段進(jìn)行查詢,我們可以使用$text進(jìn)行查詢,例如我們來查詢剛剛文本中的mongodb字符串:

db.postText.find({$text:{$search:"mongodb"}});
//輸出
{ "_id" : ObjectId("5fb297175efc1f0332d33f15"), "p_text" : "enjoy the mongodb articles on Runoob", "tags" : [ "mongodb", "runoob" ] 

如果是使用的3.X版本以下的mongo,需要使用runCommand命令來進(jìn)行查詢:

db.postText.runCommand("text",{search:"mongodb"})

除了普通的全文索引以外,我們還可能遇到多個字段聯(lián)合創(chuàng)建多文本索引的情況,這個時候就有可能遇到多個字段上的數(shù)據(jù)都滿足查詢的,這個時候我們?yōu)榱朔乐够蛘邷p少這種情況出現(xiàn),可以選擇在創(chuàng)建全文索引的時候,給每個字段指定不同的權(quán)重,權(quán)重的范圍是從1~1 000 000 000,值越小,即權(quán)重越低,如下:

db.postText.ensureIndex({p_text:"text",tags:"text"},{weights:{p_text:100,tags:2}})

這樣創(chuàng)建全文索引以后,默認(rèn)情況下p_text字段的權(quán)重是最高的,tags的權(quán)重最低

刪除索引

mongoDB規(guī)定一個集合中只能存在一個全文索引,并且由于全文索引的調(diào)整復(fù)雜,因此當(dāng)我們創(chuàng)建完畢以后,就無法修改全文索引,此時當(dāng)我們出現(xiàn)文檔結(jié)構(gòu)的調(diào)整,或者部分字段不需要進(jìn)行文本索引的時候,只能選擇刪除當(dāng)前的文本索引以后,重新建立索引,與普通的索引規(guī)則類似,全文索引的命名是按照 字段1_text_字段2_text... 的規(guī)則創(chuàng)建的,當(dāng)然我們也可以根據(jù)getIndexes函數(shù)來查詢當(dāng)前集合的索引:

db.postText.getIndexes();
//輸出
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "postText.postText"
        },
        {
                "v" : 2,
                "key" : {
                        "_fts" : "text",
                        "_ftsx" : 1
                },
                "name" : "p_text_text_tags_text",
                "ns" : "postText.postText",
                "weights" : {
                        "p_text" : 1,
                        "tags" : 100
                },
                "default_language" : "english",
                "language_override" : "language",
                "textIndexVersion" : 3
        }
]

可以看到當(dāng)前的多字段全文索引的名稱為:p_text_text_tags_text,可以和普通索引一樣使用dropIndex進(jìn)行刪除

db.postText.dropIndex("p_text_text_tags_text")

指定語言分詞器的索引

我們在創(chuàng)建文本索引的時候,可以指定切換的語言分詞,默認(rèn)情況下mongoDB的default_language選擇的是english,我們可以指定:

db.postText.ensureIndex({p_text:"text",tags:"text"},{weights:{p_text:100,tags:2},{default_language:"french"}})

這樣就創(chuàng)建了一個法語的文本索引,需要注意的是mongoDB在3.4版本開始是支持了中文索引的,但是此功能僅限在企業(yè)版的mongo中才有,而且經(jīng)過測試,mongo的中文分詞做的并不好,很多詞匯無法區(qū)分,如果真的想要在項(xiàng)目中使用文本索引的方式,可以考慮將數(shù)據(jù)同步到es中,使用分詞器進(jìn)行檢索,當(dāng)然也可以在插入文檔的時候,指定當(dāng)前文檔的語言,這樣不同的文檔之間使用的分詞器也會不一樣

地理坐標(biāo)檢索

mongoDB中支持基于地理位置的索引,可以幫助我們結(jié)合地理空間形狀以及點(diǎn)集上進(jìn)行快速高效的空間索引,而地理空間索引既可以使用平面幾何也可以使用基于球面的幾何,因此主要分為兩種,一種為2dsphere 索引,這種索引僅僅支持球面幾何索引,而另一種為2d索引,這種索引同時支持平面和球面幾何,但是2dsphere索引在使用球面幾何的查詢上會更高效和精確,因此如果我們要查詢的是基于球面地理的坐標(biāo),建議使用2dsphere索引進(jìn)行查詢。

我們先創(chuàng)建一些測試數(shù)據(jù):

db.map.insert({loc : [10, 10]});
db.map.insert({loc : [11, 10]});
db.map.insert({loc : [10, 11]});
db.map.insert({loc : [12, 15]});
db.map.insert({loc : [16, 17]});
db.map.insert({loc : [90, 90]});
db.map.insert({loc : [150, 160]});

創(chuàng)建地理索引

需要注意的是文檔的結(jié)構(gòu)是不限制的,但是我們設(shè)置為地理索引的字段的文檔格式是固定的,這里我們給loc字段設(shè)置為2d地理索引:

db.map.createIndex({ loc: "2d" })

查詢附近的點(diǎn)

假設(shè)當(dāng)前我們知道了一個坐標(biāo),希望能獲取這個坐標(biāo)附近范圍的其他點(diǎn)的位置,可以使用$near命令查看:

db.map.find({loc:{$near:[11,11]}});

此時可以看到返回的結(jié)果為:

{ "_id" : ObjectId("5fb2453d555025767cb3028a"), "loc" : [ 10, 11 ] }
{ "_id" : ObjectId("5fb2454a555025767cb30290"), "loc" : [ 11, 10 ] }
{ "_id" : ObjectId("5fb2454b555025767cb30291"), "loc" : [ 10, 11 ] }
{ "_id" : ObjectId("5fb2453d555025767cb30289"), "loc" : [ 11, 10 ] }
{ "_id" : ObjectId("5fb2453d555025767cb30288"), "loc" : [ 10, 10 ] }
{ "_id" : ObjectId("5fb2454a555025767cb3028f"), "loc" : [ 10, 10 ] }
{ "_id" : ObjectId("5fb2454b555025767cb30292"), "loc" : [ 12, 15 ] }
{ "_id" : ObjectId("5fb2453d555025767cb3028b"), "loc" : [ 12, 15 ] }
{ "_id" : ObjectId("5fb2453d555025767cb3028c"), "loc" : [ 16, 17 ] }
{ "_id" : ObjectId("5fb2454b555025767cb30293"), "loc" : [ 16, 17 ] }
{ "_id" : ObjectId("5fb2453e555025767cb3028d"), "loc" : [ 90, 90 ] }
{ "_id" : ObjectId("5fb2454b555025767cb30294"), "loc" : [ 90, 90 ] }
{ "_id" : ObjectId("5fb2454b555025767cb30295"), "loc" : [ 150, 160 ] }

我們發(fā)現(xiàn)居然把數(shù)據(jù)全部返回了,當(dāng)然我們可以在查詢的時候設(shè)置附近的范圍,單位(歐氏距離),使用$maxDistance命令:

db.map.find({loc:{$near:[11,11],$maxDistance:3}})

可以看到返回的內(nèi)容都是在3單位距離內(nèi)的點(diǎn)坐標(biāo):

{ "_id" : ObjectId("5fb2453d555025767cb3028a"), "loc" : [ 10, 11 ] }
{ "_id" : ObjectId("5fb2454a555025767cb30290"), "loc" : [ 11, 10 ] }
{ "_id" : ObjectId("5fb2454b555025767cb30291"), "loc" : [ 10, 11 ] }
{ "_id" : ObjectId("5fb2453d555025767cb30289"), "loc" : [ 11, 10 ] }
{ "_id" : ObjectId("5fb2454a555025767cb3028f"), "loc" : [ 10, 10 ] }
{ "_id" : ObjectId("5fb2453d555025767cb30288"), "loc" : [ 10, 10 ] }

查詢范圍圖形區(qū)域內(nèi)的點(diǎn)

在2d索引中,是支持限制查詢的最大距離范圍的,不過不支持最小距離,設(shè)置查詢范圍的話需要使用$geoWithin命令指定范圍和圖形,常見的圖形范圍如下:

//矩形范圍,左邊界的坐標(biāo)和右邊界的坐標(biāo)
{"$box" : [[x1, y1], [x2, y2]]}
//圓形范圍,r代表半徑長度
{"$center" : [[x1, y1], r]}
//多邊形,每個數(shù)組代表一個坐標(biāo)點(diǎn)
{"$polygon" : [[x1, y1], [x2, y2], [x3, y3],...]}

查詢矩形范圍內(nèi)的如下:

db.map.find({loc : {"$geoWithin" : {"$box" : [[9, 9], [11, 11]]}}})

查詢圓形范圍如下:

db.map.find({loc : {"$geoWithin" : {"$center" : [[10, 10], 2]}}})

查詢多邊形范圍如下:

db.map.find({loc : {"$geoWithin" : {"$polygon" : [[10, 10],[10, 12],[11, 12],[12, 12]]}}})

2d和2dsphere索引集合的差異

除了上面簡單的索引操作以外,mongodb針對這兩種索引機(jī)制,提供了很多其他的操作命令,如下:

查詢類型 幾何類型 注釋
$near(GeoJSON點(diǎn),2dsphere索引) 球面
$near(傳統(tǒng)坐標(biāo),2d索引) 平面
$nearSphere(GeoJSON點(diǎn),2dsphere索引) 球面
$nearSphere(傳統(tǒng)坐標(biāo),2d索引) 球面 使用GeoJSON點(diǎn)替換
$geoWithin:{$geometry:...} 球面
$geoWithin:{$box:...} 平面
$geoWithin:{$polygon:...} 平面
$geoWithin:{$center:...} 平面
$geoWithin:{$centerSphere:...} 球面
$geoIntersects 球面

除此之外,兩個索引數(shù)據(jù)之間需要的格式也是有差異的,上面我們使用的2d索引只需要索引字段的內(nèi)容符合[x,y]坐標(biāo)格式即可,而如果我們需要使用2dsphere索引的話,我們需要維護(hù)GeoJSON格式的坐標(biāo)信息,格式大概為:

{ type: 'GeoJSON type' , coordinates: 'coordinates'} 

其中type指的是類型,常見的如Point、LineString、Polygon等,我們用得地圖索引使用的type就是Point類型,coordinates 則是一個坐標(biāo)數(shù)組,我們來插入一條數(shù)據(jù),如下:

db.map2.insert({name:"A",sp:{type:"Point",coordinates:[105.754484701156,41.689607057699]}})

其中sp字段就是我們需要的GeoJSON格式的數(shù)據(jù)

GridFS存儲文件

GridFS是MongoDB的一種存儲機(jī)制,用來存儲大型二進(jìn)制文件,其優(yōu)點(diǎn)如下:

1.使用GridFS能夠簡化你的棧。如果已經(jīng)在使用MongoDB,那么可以使用GridFS來代替獨(dú)立的文件存儲工具

2.GridFS會自動平衡已有的復(fù)制或者設(shè)置為自動分片,所以對文件存儲的故障轉(zhuǎn)移、備份或者橫向擴(kuò)展會更加容易

3.當(dāng)用戶上傳文件的時候,GridFS可以避免一些文件系統(tǒng)的問題,比如某個目錄下無法存儲大量文件或者大量的大內(nèi)存文件

4.在GridFS中,文件存儲的集中度比較高,因?yàn)樵贛ongoDB中,一個數(shù)據(jù)文件是2GB的方式分割的

除此之外,GridFS也有一些缺陷,這也是目前主流的文件系統(tǒng)中幾乎很少考慮GridFS的原因:

1.GridFS的性能比較低,比起直接搭建文件存儲系統(tǒng),進(jìn)行訪問文件的速度要慢上一些

2.GridFS不支持直接進(jìn)行文件的修改,如果我們需要修改某個文件,必須先刪除以后,再重新保存才可以

3.GridFS無法支持同時保存多個文件,因此在并發(fā)情況下,無法同時對多個文件進(jìn)行加鎖

使用GridFS

想要使用GridFS比較簡單的方式就是mongofiles工具了,這個一般在mongoDB的發(fā)行版里面都有,可以直接使用,除此之外也可以根據(jù)mongoDB的驅(qū)動實(shí)現(xiàn)各語言的GridFS文件上傳、下載

我們可以通過mongofiles --help命令來查看相關(guān)的文件操作的命令,如下:

mongofiles  --help

可以看到,我們操作mongofiles的命令如下:

mongofiles <options> <command> <filename or _id>

而在操作中,我們只需要指定options,command以及文件名即可

上傳

我們先在/up_files目錄下創(chuàng)建一個文件:

vim up_test.txt
//上傳
 mongofiles put up_test.txt 
//響應(yīng)
2020-12-22T01:08:03.596+0800    connected to: mongodb://localhost/
2020-12-22T01:08:03.713+0800    added gridFile: up_test.txt

可以看到上傳成功了,接著我們來查看一下當(dāng)前的文件列表有木有這個文件,查看列表使用list命令:

mongofiles list
//響應(yīng)
2020-12-22T01:08:45.289+0800    connected to: mongodb://localhost/
up_test.txt     31

可以看到我們上傳的up_test.txt文件已經(jīng)上傳了,并且顯示出了文件大小,31字節(jié),現(xiàn)在我們把本地的文件刪除,嘗試從mongo中下載下來(下載命令是get):

rm -rf up_test.txt
ls -l
//可以看到當(dāng)前目錄下什么文件都沒有了,開始下載
mongofiles get up_test.txt
//再次查看目錄
ls -l
-rw-r--r--. 1 root root 31 12?? 22 01:22 up_test.txt

除此之外,我們還可以在GridFS中進(jìn)行文件搜索以及刪除遠(yuǎn)端的文件,分別是search命令和delete命令,如下:

mongofiles search up
//結(jié)果
2020-12-22T01:37:25.954+0800    connected to: mongodb://localhost/
up_test.txt     31

接著我們把搜索到的文件列表進(jìn)行刪除

mongofiles delete up_test.txt
//刪除全部up開頭的文件
2020-12-22T01:38:25.017+0800    connected to: mongodb://localhost/
2020-12-22T01:38:25.019+0800    successfully deleted all instances of 'up_test.txt' from GridFS
GridFS解惑

GridFS是一種輕量級的文件存儲規(guī)范,用于存儲MongoDB中的普通文檔?;旧螹ongoDB不會對GridFS里面的文件做任何特殊處理,這些處理需要用戶自己處理或者部分由MongoDB的驅(qū)動實(shí)現(xiàn)。

GridFS的原理是:**可以將大文件分割為多個比較大的chunk塊,,一般為256k/個,每個chunk將作為MongoDB的一個文檔(document)被存儲在chunks集合中 **。因?yàn)镸ongoDB支持在文檔中存儲二進(jìn)制,因此可以把存儲塊的成本降低很多。除了拆分的塊以外,Mongo中還有個文檔用于記錄存儲這些塊文件的元信息(默認(rèn)是fs.files集合 )。而這些塊會存儲在一個特殊的集合中,默認(rèn)使用的是fs.chunks,也可以配置修改為其他的集合,集合中記錄塊的信息比較簡單,fs.files集合的文檔內(nèi)容如下:

{
   "filename": "up_test.txt",
   "chunkSize": NumberInt(31),
   "uploadDate": ISODate("2020-12-21T16:32:33.557Z"),
   "md5": "7b762939321e146569b07f72c62cca4f",
   "length": NumberInt(31)
}

可以看到,這里定義了文件的名稱,拆分的chunk塊大小,以及文件本身的大小,上傳的時間以及文件的md5,用于過濾重復(fù)的文件,除此之外,我們可以查看fs.chunks集合的文檔,如下:

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

可以看到這里定義了幾個屬性,大概信息如下:

files_id:塊所屬文件的元信息
n:塊在文件中的相對位置
data:塊中包含的二進(jìn)制數(shù)據(jù)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容