學習9:MongoDB知識

MongoDB學習筆記

1 基本介紹

  • 基本概念

MongoDB**是一種面向文檔數據庫管理系統,由C++語言編寫的,是一個基於分佈式文件存儲的開源數據庫系統。2007年10月,MongoDB由10gen團隊所發展。2009年2月首度推出。在高負載的狀況下,添加更多的節點,能夠保證服務器性能。MongoDB 旨在爲WEB應用提供可擴展的高性能數據存儲解決方案。MongoDB 將數據存儲爲一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔相似於 JSON 對象。字段值能夠包含其餘文檔,數組及文檔數組。php

  • 優缺點

優勢java

  • 文檔結構的存儲方式,可以更便捷的獲取數據
  • 內置GridFS,支持大容量的存儲:GridFS是一個出色的分佈式文件系統,能夠支持海量的數據存儲。 內置了GridFS了MongoDB,可以知足對大數據集的快速範圍查詢。
  • 海量數據下,性能優越:在使用場合下,千萬級別的文檔對象,近10G的數據,對有索引的ID的查詢不會比mysql慢,而對非索引字段的查詢,則是全面勝出。 mysql實際沒法勝任大數據量下任意字段的查詢,而mongodb的查詢性能實在讓我驚訝。寫入性能一樣很使人滿意。
  • 動態查詢
  • 全索引支持,擴展到內部對象和內嵌數組:索引一般可以極大的提升查詢的效率,若是沒有索引,MongoDB在讀取數據時必須掃描集合中的每一個文件並選取那些符合查詢條件的記錄。這種掃描全集合的查詢效率是很是低的,特別在處理大量的數據時,查詢能夠要花費幾十秒甚至幾分鐘,這對網站的性能是很是致命的。索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構。
  • 查詢記錄分析
  • 快速,就地更新
  • 高效存儲二進制大對象 (好比照片和視頻)
  • 複製(複製集)和支持自動故障恢復
  • 內置 Auto- Sharding 自動分片支持雲級擴展性,分片簡單
  • MapReduce 支持複雜聚合:主要用於處理數據(諸如統計平均值,求和等),並返回計算後的數據結果。有點相似sql語句中的 count(*)。
  • 商業支持,培訓和諮詢

缺點mysql

  • 不支持事務操做:事務要求嚴格的系統(若是銀行系統)確定不能用它。
  • MongoDB沒有如MySQL那樣成熟的維護工具
  • 沒法進行關聯表查詢,不適用於關係多的數據
  • 複雜聚合操做經過mapreduce建立,速度慢
  • 模式自由,自由靈活的文件存儲格式帶來的數據錯
  • MongoDB 在你刪除記錄後不會在文件系統回收空間。除非你刪掉數據庫。可是空間沒有被浪費

  • 關係型數據庫遵循ACID

1559180960324

  • 分佈式計算優缺點

1559180993023

  • NoSQL:not only SQL優缺點

1559181053403

  • NoSQL數據庫分類

1559181242965

  • MongoDB:C++語言編寫,開源,高負載添加節點保證服務器性能。將數據存儲爲文檔,於分佈式文件存儲的數據庫。下載地址:http://www.mongodb.org/downloads
  • MongoDB啓動參數

1559181912166

  • 配置MongoDB

解壓下載https://www.mongodb.com/download-center/community的ZIP包,並更改文件名爲mongodb,在其同目錄下建立文件夾data和data\db,log和mongo.log。git

  • 打開cmd 進入cd mongodb\bin,執行下面命令啓動網絡:
mongod --dbpath D:\mongodb\data\db --logpath=D:\mongodb\log\mongodb.log --logappend

最後,再次打開cmd 進入cd mongodb\bin,執行下面命令:mongogithub

1559186650872

在瀏覽器中打開地址:正則表達式

1559186656937

  • MongoDB概念解析

1559186886391

1559186928121

  • 數據庫命令
    • "show dbs" 命令顯示全部數據的列表。
    • "db" 命令顯示當前數據庫對象或集合
    • "use"命令,能夠鏈接到一個指定的數據庫。
  • 數據庫命名規範

1559187123567

  • 文檔(行):文檔是一個鍵值(key-value)對(即BSON)。MongoDB 的文檔不須要設置相同的字段,而且相同的字段不須要相同的數據類型,這與關係型數據庫有很大的區別,也是 MongoDB 很是突出的特色。
  • 集合(表):集合就是 MongoDB 文檔組,相似於 RDBMS (關係數據庫管理系統:Relational Database Management System)中的表格。

1559187565122

  • 數據類型

1559187668921

  • mongodb鏈接

用戶名和密碼鏈接到MongoDB,'username:password@hostname/dbname'sql

2 MongoDB操做

  • 建立數據庫 use DATABASE_NAME
  • 插入數據:

1559188244044

  • 刪除數據庫: db.dropDatabase()

1559188632034

  • 刪除集合 db.collection.drop()
  • 插入文檔 : db.COLLECTION_NAME.insert(document)
  • 更新文檔: db.collection.update( criteria, objNew, upsert, multi )

1559194456898

  • 查找文檔 db.userdetails.find(),find() 方法以非結構化的方式來顯示全部文檔。還有一個 findOne() 方法,它只返回一個文檔。

1559194566238

易懂的讀取pretty(),mongodb

1559194957319

  • 刪除文檔 remove() 方法,
db.collection.remove(
   <query>,
   <justOne>
)

1559194705713

1559194838850

1559194860318

  • MongoDB 與 RDBMS Where 語句比較

1559195061183

  • MongoDB AND條件:MongoDB 的 find() 方法能夠傳入多個鍵(key),每一個鍵(key)以逗號隔開,及常規 SQL 的 AND 條件。語法格式以下:
db.col.find({key1:value1, key2:value2}).pretty()
  • OR查詢條件:MongoDB OR 條件語句使用了關鍵字 $or,語法格式以下:
>db.col.find(
   {
      $or: [
         {key1: value1}, {key2:value2}
      ]
   }
).pretty()
  • $type操做符:操做符是基於BSON類型來檢索集合中匹配的數據類型,並返回結果。

1559195634297

1559195692828

  • limit與skip,limit()方法接受一個數字參數,該參數指定從MongoDB中讀取的記錄條數。
db.COLLECTION_NAME.find().limit(NUMBER)

1559196000013

skip()方法來跳過指定數量的數據,skip方法一樣接受一個數字參數做爲跳過的記錄條數。docker

db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

1559196111264

  • 排序:sort()方法能夠經過參數指定排序的字段,並使用 1 和 -1 來指定排序的方式,其中 1 爲升序排列,而-1是用於降序排列。
db.COLLECTION_NAME.find().sort({KEY:1})

1559196274507

  • 索引: ensureIndex() 方法來建立索引。語法中 Key 值爲你要建立的索引字段,1爲指定按升序建立索引,若是你想按降序來建立索引指定爲-1便可。
db.COLLECTION_NAME.ensureIndex({KEY:1})

1559196456301

  • 聚合:處理數據(諸如統計平均值,求和等),並返回計算後的數據結果。有點相似sql語句中的 count(*)。聚合的方法使用aggregate()。
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

1559197043081

1559197060737

  • 管道

1559197168435

1559197245689

  • 複製,複製是將數據同步在多個服務器的過程。複製提供了數據的冗餘備份,並在多個服務器上存儲數據副本,提升了數據的可用性, 並能夠保證數據的安全性。複製還容許您從硬件故障和服務中斷中恢復數據。

1559267370335

1559267428165

1559267479014

mongod --port 27017 --dbpath D:\mongodb\data\db --logpath=D:\mongodb\log\mongodb.log --replSet rs0

以上實例會啓動一個名爲rs0的MongoDB實例,其端口號爲27017。shell

啓動後打開命令提示框並鏈接上mongoDB服務。

在Mongo客戶端使用命令rs.initiate()來啓動一個新的副本集。

咱們可使用rs.conf()來查看副本集的配置

查看副本集姿態使用 rs.status() 命令

1559267960209

1559267982791

D:\mongodb\bin>mongo
MongoDB shell version v4.1.11-262-gc237f4c
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("7109348e-cade-4128-af30-7cf8776302a9") }
MongoDB server version: 4.1.11-262-gc237f4c

# 添加副本集
> rs.add("mongod1.net:27017")
2019-05-30T18:57:26.058-0700 E  QUERY    [js] uncaught exception: Error: assert failed : no config object retrievable from local.system.replset :
doassert@src/mongo/shell/assert.js:20:14
assert@src/mongo/shell/assert.js:152:9
rs.add@src/mongo/shell/utils.js:1441:5
@(shell):1:1

# 查看當前運行是不是主節點
> db.isMaster()
{
        "ismaster" : false,
        "secondary" : false,
        "info" : "Does not have a valid replica set config",
        "isreplicaset" : true,
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 100000,
        "localTime" : ISODate("2019-05-31T01:57:40.632Z"),
        "logicalSessionTimeoutMinutes" : 30,
        "connectionId" : 1,
        "minWireVersion" : 0,
        "maxWireVersion" : 8,
        "readOnly" : false,
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(0, 0),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(0, 0)
}

# 啓動一個新的副本集
> rs.initiate()

# 查看副本集的配置
rs0:SECONDARY> rs.conf()


# 查看副本集姿態
rs0:PRIMARY> rs.status()
  • MongoDB分片,另外一種集羣,就是分片技術,能夠知足MongoDB數據量大量增加的需求。當MongoDB存儲海量的數據時,一臺機器可能不足以存儲數據也足以提供可接受的讀寫吞吐量。就能夠經過在多臺機器上分割數據,使得數據庫系統能存儲和處理更多的數據。

1559268249351

1559268281459

  • 分片實例

1559268398976

1559268408273

1559268423437

1559268467386

  • MongoDB數據備份:mongodbdump

    使用mongodump命令來備份MongoDB數據。該命令能夠導出全部數據到指定目錄中。mongodump命令能夠經過參數指定導出的數據量級轉存的服務器。

15592686717731559269163513

1559269178020

1559269257022

  • MongoDB數據恢復,mongodbstore

1559269316842

  • MongoDB監控

mongostat 和 mongotop 兩個命令來監控MongoDB的運行狀況。

1559269505961

1559269658919

1559269778023

3鏈接MongoDB數據庫

3.1 Java代碼鏈接MongoDB數據庫

環境配置,在Java程序中若是要使用MongoDB,你須要確保已經安裝了Java環境及MongoDB JDBC 驅動。

  • 首先你必須下載mongo jar包,下載地址:https://github.com/mongodb/mongo-java-driver/downloads, 請確保下載最新版本。
  • 你須要將mongo.jar包含在你的 classpath 中。。
  • 鏈接數據庫,你須要指定數據庫名稱,若是指定的數據庫不存在,mongo會自動建立數據庫。
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.WriteConcern;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBCursor;
import com.mongodb.ServerAddress;
import java.util.Arrays;

public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 鏈接到 mongodb 服務
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         // 鏈接到數據庫
         DB db = mongoClient.getDB( "test" );
         System.out.println("Connect to database successfully");
         boolean auth = db.authenticate(myUserName, myPassword);
         System.out.println("Authentication: "+auth);
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}
  • 使用com.mongodb.DB類中的createCollection()來建立集合
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 鏈接到 mongodb 服務
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         // 鏈接到數據庫
         DB db = mongoClient.getDB( "test" );
     System.out.println("Connect to database successfully");
         boolean auth = db.authenticate(myUserName, myPassword);
     System.out.println("Authentication: "+auth);
         DBCollection coll = db.createCollection("mycol");
         System.out.println("Collection created successfully");
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}
  • 使用com.mongodb.DBCollection類的 getCollection() 方法來獲取一個集合
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 鏈接到 mongodb 服務
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         // 鏈接到數據庫
         DB db = mongoClient.getDB( "test" );
     System.out.println("Connect to database successfully");
         boolean auth = db.authenticate(myUserName, myPassword);
     System.out.println("Authentication: "+auth);
         DBCollection coll = db.createCollection("mycol");
         System.out.println("Collection created successfully");
         DBCollection coll = db.getCollection("mycol");
         System.out.println("Collection mycol selected successfully");
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}
  • 使用com.mongodb.DBCollection類的 insert() 方法來插入一個文檔
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 鏈接到 mongodb 服務
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         // 鏈接到數據庫
         DB db = mongoClient.getDB( "test" );
     System.out.println("Connect to database successfully");
         boolean auth = db.authenticate(myUserName, myPassword);
     System.out.println("Authentication: "+auth);         
         DBCollection coll = db.getCollection("mycol");
         System.out.println("Collection mycol selected successfully");
         BasicDBObject doc = new BasicDBObject("title", "MongoDB").
            append("description", "database").
            append("likes", 100).
            append("url", "//www.w3cschool.cn/mongodb/").
            append("by", "w3cschool.cn");
         coll.insert(doc);
         System.out.println("Document inserted successfully");
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}
  • 使用com.mongodb.DBCollection類中的 find() 方法來獲取集合中的全部文檔。
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
        // 鏈接到 mongodb 服務
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
          // 鏈接到數據庫
         DB db = mongoClient.getDB( "test" );
     System.out.println("Connect to database successfully");
         boolean auth = db.authenticate(myUserName, myPassword);
     System.out.println("Authentication: "+auth);         
         DBCollection coll = db.getCollection("mycol");
         System.out.println("Collection mycol selected successfully");
         DBCursor cursor = coll.find();
         int i=1;
         while (cursor.hasNext()) { 
            System.out.println("Inserted Document: "+i); 
            System.out.println(cursor.next()); 
            i++;
         }
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}
  • 使用 com.mongodb.DBCollection 類中的 update() 方法來更新集合中的文檔
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
     // 鏈接到Mongodb服務
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         // 鏈接到你的數據庫
         DB db = mongoClient.getDB( "test" );
     System.out.println("Connect to database successfully");
         boolean auth = db.authenticate(myUserName, myPassword);
     System.out.println("Authentication: "+auth);         
         DBCollection coll = db.getCollection("mycol");
         System.out.println("Collection mycol selected successfully");
         DBCursor cursor = coll.find();
         while (cursor.hasNext()) { 
            DBObject updateDocument = cursor.next();
            updateDocument.put("likes","200")
            coll.update(updateDocument); 
         }
         System.out.println("Document updated successfully");
         cursor = coll.find();
         int i=1;
         while (cursor.hasNext()) { 
            System.out.println("Updated Document: "+i); 
            System.out.println(cursor.next()); 
            i++;
         }
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}
  • 使用com.mongodb.DBCollection類中的 findOne()方法來獲取第一個文檔,而後使用remove 方法刪除
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
     // 鏈接到Mongodb服務
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         // 鏈接到你的數據庫
         DB db = mongoClient.getDB( "test" );
     System.out.println("Connect to database successfully");
         boolean auth = db.authenticate(myUserName, myPassword);
     System.out.println("Authentication: "+auth);         
         DBCollection coll = db.getCollection("mycol");
         System.out.println("Collection mycol selected successfully");
         DBObject myDoc = coll.findOne();
         coll.remove(myDoc);
         DBCursor cursor = coll.find();
         int i=1;
         while (cursor.hasNext()) { 
            System.out.println("Inserted Document: "+i); 
            System.out.println(cursor.next()); 
            i++;
         }
         System.out.println("Document deleted successfully");
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}

4 MongoDB高級教程

4.1 關係

MongoDB 的關係表示多個文檔之間在邏輯上的相互聯繫。文檔間能夠經過嵌入和引用來創建聯繫。MongoDB 中的關係能夠是:

  • 1:1 (1對1)
  • 1: N (1對多)
  • N: 1 (多對1)
  • N: N (多對多)

一個用戶能夠有多個地址,因此是一對多的關係。

1559271548446

  • 使用嵌入式方法,咱們能夠把用戶地址嵌入到用戶的文檔中
"_id":ObjectId("52ffc33cd85242f436000001"),
   "contact": "987654321",
   "dob": "01-01-1991",
   "name": "Tom Benzamin",
   "address": [
      {
         "building": "22 A, Indiana Apt",
         "pincode": 123456,
         "city": "Los Angeles",
         "state": "California"
      },
      {
         "building": "170 A, Acropolis Apt",
         "pincode": 456789,
         "city": "Chicago",
         "state": "Illinois"
      }]
}

數據保存在單一文檔中,比較容易的獲取很維護數據。 你能夠這樣查詢用戶的地址:

>db.users.findOne({"name":"Tom Benzamin"},{"address":1})

這種數據結構的缺點是,若是用戶和用戶地址在不斷增長,數據量不斷變大,會影響讀寫性能。

  • 引用式關係,把用戶數據文檔和用戶地址數據文檔分開,經過引用文檔的 id 字段來創建關係。
{
   "_id":ObjectId("52ffc33cd85242f436000001"),
   "contact": "987654321",
   "dob": "01-01-1991",
   "name": "Tom Benzamin",
   "address_ids": [
      ObjectId("52ffc4a5d85242602e000000"),
      ObjectId("52ffc4a5d85242602e000001")
   ]
}

須要兩次查詢,第一次查詢用戶地址的對象id(ObjectId),第二次經過查詢的id獲取用戶的詳細地址信息。

>var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})

4.2 MapReduce

1559272583016

  • 使用MapReduce

1559272627022

1559272672162

1559272811159

  • 全文檢索,MongoDB 在 2.6 版本之後是默認開啓全文檢索的
  • 建立全文索引

考慮如下 posts 集合的文檔數據,包含了文章內容(post_text)及標籤(tags):

{
   "post_text": "enjoy the mongodb articles on w3cschool.cn",
   "tags": [
      "mongodb",
      "w3cschool"
   ]
}

咱們能夠對 post_text 字段創建全文索引,這樣咱們能夠搜索文章內的內容:

>db.posts.ensureIndex({post_text:"text"})

  • 使用全文索引

如今咱們已經對 post_text 創建了全文索引,咱們能夠搜索文章中的關鍵詞w3cschool.cn:

>db.posts.find({$text:{$search:"w3cschool.cn"}})

如下命令返回了以下包含NoSQL關鍵詞的文檔數據:

D:\mongodb\bin>mongo
MongoDB shell version v4.1.11-262-gc237f4c

> show dbs
admin        0.000GB
config       0.000GB
local        0.000GB
myinfo       0.000GB
w3cschooldb  0.000GB
youj         0.000GB
> use youj
switched to db youj
> db.col.find()
{ "_id" : ObjectId("5cef550377781c00a00de949"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 數據庫", "by" : "w3cschool", "url" : "http://www.w3cschool.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }
{ "_id" : ObjectId("5cef690677781c00a00de94a"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 數據庫", "by" : "w3cschool", "url" : "http://www.w3cschool.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }

> db.col.ensureIndex({description:"text"})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.col.find({$text:{$search:"NoSQL"}})
{ "_id" : ObjectId("5cef690677781c00a00de94a"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 數據庫", "by" : "w3cschool", "url" : "http://www.w3cschool.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }
{ "_id" : ObjectId("5cef550377781c00a00de949"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 數據庫", "by" : "w3cschool", "url" : "http://www.w3cschool.cn", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }
>

4.3 刪除全文索引

刪除已存在的全文索引,可使用 find 命令查找索引名:

>db.col.getIndexes()

經過以上命令獲取索引名,本例的索引名爲post_text_text,執行如下命令來刪除索引:

> db.col.dropIndex('description_text')

4.4 正則

使用 $regex 操做符來設置匹配字符串的正則表達式。

  • 使用正則表達式,使用正則查找包含 w3cschool.cn 字符串的文章:
>db.posts.find({post_text:{$regex:"w3cschool.cn"}})

以上查詢也能夠寫爲:

>db.posts.find({post_text:/w3cschool.cn/})
  • 不區分大小寫的正則表達式

若是檢索須要不區分大小寫,咱們能夠設置 $options 爲 $i。如下命令將查找不區分大小寫的字符串 w3cschool.cn:

>db.posts.find({post_text:{$regex:"w3cschool.cn",$options:"$i"}})

集合中會返回全部包含字符串 w3cschool.cn 的數據,且不區分大小寫:

{
   "_id" : ObjectId("53493d37d852429c10000004"),
   "post_text" : "hey! this is my post on  W3Cschool.cc", 
   "tags" : [ "tutorialspoint" ]
}
  • 數組元素使用正則表達式

這在標籤的實現上很是有用,若是你須要查找包含以 tutorial 開頭的標籤數據(tutorial 或 tutorials 或 tutorialpoint 或 tutorialphp), 你可使用如下代碼:

>db.posts.find({tags:{$regex:"tutorial"}})
  • 優化正則表達式查詢

若是你的文檔中字段設置了索引,那麼使用索引相比於正則表達式匹配查找全部的數據查詢速度更快。

若是正則表達式是前綴表達式,全部匹配的數據將以指定的前綴字符串爲開始。例如: 若是正則表達式爲^tut ,查詢語句將查找以 tut 爲開頭的字符串。

4.5 GridFS

GridFS 用於存儲和恢復那些超過16M(BSON文件限制)的文件(如:圖片、音頻、視頻等)。也是文件存儲的一種方式,可是它是存儲在MonoDB的集合中。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 添加文件

如今咱們使用 GridFS 的 put 命令來存儲 mp3 文件。 調用 MongoDB 安裝目錄下bin的 mongofiles.exe工具。

打開命令提示符,進入到MongoDB的安裝目錄的bin目錄中,找到mongofiles.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個區塊中。

4.6 自動增加

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})
  • 建立 Javascript 函數

建立函數 getNextSequenceValue 來做爲序列名的輸入, 指定的序列會自動增加 1 並返回最新序列值。在本文的實例中序列名爲 productid 。

>function getNextSequenceValue(sequenceName){
   var sequenceDocument = db.counters.findAndModify(
      {
         query:{_id: sequenceName },
         update: {$inc:{sequence_value:1}},
         new:true
      });
   return sequenceDocument.sequence_value;
}
  • 使用 Javascript 函數

使用 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.prodcuts.find()

以上命令將返回如下結果,咱們發現 _id 字段是自增加的:

{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}

{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }
相關文章
相關標籤/搜索