MongoDB學習筆記
1 基本介紹
- 基本概念
MongoDB**是一種面向文檔的數據庫管理系統,由C++語言編寫的,是一個基於分布式文件存儲的開源數據庫系統。2007年10月,MongoDB由10gen團隊所發展。2009年2月首度推出。在高負載的情況下,添加更多的節點,可以保證服務器性能。MongoDB 旨在為WEB應用提供可擴展的高性能數據存儲解決方案。MongoDB 將數據存儲為一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔類似於 JSON 對象。字段值可以包含其他文檔,數組及文檔數組。
- 優缺點
優點
- 文檔結構的存儲方式,能夠更便捷的獲取數據
- 內置GridFS,支持大容量的存儲:GridFS是一個出色的分布式文件系統,可以支持海量的數據存儲。 內置了GridFS了MongoDB,能夠滿足對大數據集的快速范圍查詢。
- 海量數據下,性能優越:在使用場合下,千萬級別的文檔對象,近10G的數據,對有索引的ID的查詢不會比mysql慢,而對非索引字段的查詢,則是全面勝出。 mysql實際無法勝任大數據量下任意字段的查詢,而mongodb的查詢性能實在讓我驚訝。寫入性能同樣很令人滿意。
- 動態查詢
- 全索引支持,擴展到內部對象和內嵌數組:索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取數據時必須掃描集合中的每個文件並選取那些符合查詢條件的記錄。這種掃描全集合的查詢效率是非常低的,特別在處理大量的數據時,查詢可以要花費幾十秒甚至幾分鍾,這對網站的性能是非常致命的。索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構。
- 查詢記錄分析
- 快速,就地更新
- 高效存儲二進制大對象 (比如照片和視頻)
- 復制(復制集)和支持自動故障恢復
- 內置 Auto- Sharding 自動分片支持雲級擴展性,分片簡單
- MapReduce 支持復雜聚合:主要用於處理數據(諸如統計平均值,求和等),並返回計算后的數據結果。有點類似sql語句中的 count(*)。
- 商業支持,培訓和咨詢
缺點
- 不支持事務操作:事務要求嚴格的系統(如果銀行系統)肯定不能用它。
- MongoDB沒有如MySQL那樣成熟的維護工具
- 無法進行關聯表查詢,不適用於關系多的數據
- 復雜聚合操作通過mapreduce創建,速度慢
- 模式自由,自由靈活的文件存儲格式帶來的數據錯
- MongoDB 在你刪除記錄后不會在文件系統回收空間。除非你刪掉數據庫。但是空間沒有被浪費
- 關系型數據庫遵循ACID
- 分布式計算優缺點
- NoSQL:not only SQL優缺點
- NoSQL數據庫分類
- MongoDB:C++語言編寫,開源,高負載添加節點保證服務器性能。將數據存儲為文檔,於分布式文件存儲的數據庫。下載地址:http://www.mongodb.org/downloads
- MongoDB啟動參數
- 配置MongoDB
解壓下載https://www.mongodb.com/download-center/community的ZIP包,並更改文件名為mongodb,在其同目錄下創建文件夾data和data\db,log和mongo.log。
- 打開cmd 進入cd mongodb\bin,執行下面命令啟動網絡:
mongod --dbpath D:\mongodb\data\db --logpath=D:\mongodb\log\mongodb.log --logappend
最后,再次打開cmd 進入cd mongodb\bin,執行下面命令:mongo
在瀏覽器中打開地址:
- MongoDB概念解析
- 數據庫命令
- "show dbs" 命令顯示所有數據的列表。
- "db" 命令顯示當前數據庫對象或集合
- "use"命令,可以連接到一個指定的數據庫。
- 數據庫命名規范
- 文檔(行):文檔是一個鍵值(key-value)對(即BSON)。MongoDB 的文檔不需要設置相同的字段,並且相同的字段不需要相同的數據類型,這與關系型數據庫有很大的區別,也是 MongoDB 非常突出的特點。
- 集合(表):集合就是 MongoDB 文檔組,類似於 RDBMS (關系數據庫管理系統:Relational Database Management System)中的表格。
- 數據類型
- mongodb連接
用戶名和密碼連接到MongoDB,'username:password@hostname/dbname'
2 MongoDB操作
- 創建數據庫 use DATABASE_NAME
- 插入數據:
- 刪除數據庫: db.dropDatabase()
- 刪除集合 db.collection.drop()
- 插入文檔 : db.COLLECTION_NAME.insert(document)
- 更新文檔: db.collection.update( criteria, objNew, upsert, multi )
- 查找文檔 db.userdetails.find(),find() 方法以非結構化的方式來顯示所有文檔。還有一個 findOne() 方法,它只返回一個文檔。
易懂的讀取pretty(),
- 刪除文檔 remove() 方法,
db.collection.remove(
<query>,
<justOne>
)
- MongoDB 與 RDBMS Where 語句比較
- 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類型來檢索集合中匹配的數據類型,並返回結果。
- limit與skip,limit()方法接受一個數字參數,該參數指定從MongoDB中讀取的記錄條數。
db.COLLECTION_NAME.find().limit(NUMBER)
skip()方法來跳過指定數量的數據,skip方法同樣接受一個數字參數作為跳過的記錄條數。
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
- 排序:sort()方法可以通過參數指定排序的字段,並使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而-1是用於降序排列。
db.COLLECTION_NAME.find().sort({KEY:1})
- 索引: ensureIndex() 方法來創建索引。語法中 Key 值為你要創建的索引字段,1為指定按升序創建索引,如果你想按降序來創建索引指定為-1即可。
db.COLLECTION_NAME.ensureIndex({KEY:1})
- 聚合:處理數據(諸如統計平均值,求和等),並返回計算后的數據結果。有點類似sql語句中的 count(*)。聚合的方法使用aggregate()。
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
- 管道
- 復制,復制是將數據同步在多個服務器的過程。復制提供了數據的冗余備份,並在多個服務器上存儲數據副本,提高了數據的可用性, 並可以保證數據的安全性。復制還允許您從硬件故障和服務中斷中恢復數據。
mongod --port 27017 --dbpath D:\mongodb\data\db --logpath=D:\mongodb\log\mongodb.log --replSet rs0
以上實例會啟動一個名為rs0的MongoDB實例,其端口號為27017。
啟動后打開命令提示框並連接上mongoDB服務。
在Mongo客戶端使用命令rs.initiate()來啟動一個新的副本集。
我們可以使用rs.conf()來查看副本集的配置
查看副本集姿態使用 rs.status() 命令
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存儲海量的數據時,一台機器可能不足以存儲數據也足以提供可接受的讀寫吞吐量。就可以通過在多台機器上分割數據,使得數據庫系統能存儲和處理更多的數據。
- 分片實例
-
MongoDB數據備份:mongodbdump
使用mongodump命令來備份MongoDB數據。該命令可以導出所有數據到指定目錄中。mongodump命令可以通過參數指定導出的數據量級轉存的服務器。
、
- MongoDB數據恢復,mongodbstore
- MongoDB監控
mongostat 和 mongotop 兩個命令來監控MongoDB的運行情況。
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 (多對多)
一個用戶可以有多個地址,所以是一對多的關系。
- 使用嵌入式方法,我們可以把用戶地址嵌入到用戶的文檔中
"_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
- 使用MapReduce
- 全文檢索,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" }