一、關係 MongoDB 的關係表示多個文檔之間在邏輯上的相互聯繫。文檔間可以通過嵌入和引用來建立聯繫。MongoDB 中的關係可以是:1對1,1對多,多對1,多對多。 一個用戶可以用多個地址,這是典型的一對多關係。 user文檔可以是: { "_id":ObjectId("52ffc33cd852
一、關係
MongoDB 的關係表示多個文檔之間在邏輯上的相互聯繫。文檔間可以通過嵌入和引用來建立聯繫。MongoDB 中的關係可以是:1對1,1對多,多對1,多對多。
一個用戶可以用多個地址,這是典型的一對多關係。
user文檔可以是:
{ "_id":ObjectId("52ffc33cd85242f436000001"), "name": "Tom Hanks", "contact": "987654321", "dob": "01-01-1991" }
address文檔可以是:
{ "_id":ObjectId("52ffc4a5d85242602e000000"), "building": "22 A, Indiana Apt", "pincode": 123456, "city": "Los Angeles", "state": "California" }
1、嵌入式關係
使用嵌入式方法,可以把地址文檔嵌入到用戶的文檔中
{ "_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})
這種數據結構的缺點是,如果用戶和用戶地址在不斷增加,數據量不斷變大,會影響讀寫性能。
2、引用式方法
這種方法類似於關係型資料庫中的外鍵,將address的_id存到user文檔中
{ "_id":ObjectId("52ffc33cd85242f436000001"), "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin", "address_ids": [ ObjectId("52ffc4a5d85242602e000000"), ObjectId("52ffc4a5d85242602e000001") ] }
我們可以讀取這些用戶地址的對象id(ObjectId)來獲取用戶的詳細地址信息。這種方法需要兩次查詢,第一次查詢用戶地址的對象id(ObjectId),第二次通過查詢的id獲取用戶的詳細地址信息。
var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1}) var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})
二、資料庫引用
mongodb的引用有兩種:手動引用(Manual References)與 DBRefs
如果我們在不同的集合中 (address_home, address_office, address_mailing, 等)存儲不同的地址(住址,辦公室地址,郵件地址等)。這時候我們在調用不同地址時,也需要指定集合,一個文檔從多個集合引用文檔,我們應該使用 DBRefs。
DBRef的形式:
{ $ref : , $id : , $db : }
其中$ref:集合名稱,$id:引用的id,$db:資料庫名稱(可選)。
以下實例中用戶數據文檔使用了 DBRef, 欄位 address:
{ "_id":ObjectId("53402597d852426020000002"), "address": { "$ref": "address_home", "$id": ObjectId("534009e4d852427820000002"), "$db": "w3cschoolcc"}, "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin" }
address DBRef 欄位指定了引用的地址文檔是在 address_home 集合下的 w3cschoolcc 資料庫,id 為 534009e4d852427820000002。
以下代碼中,我們通過指定 $ref 參數(address_home 集合)來查找集合中指定id的用戶地址信息:
var user = db.users.findOne({"name":"Tom Benzamin"}) var dbRef = user.address db[dbRef.$ref].findOne({"_id":(dbRef.$id)})
以上實例返回了 address_home 集合中的地址數據:
{ "_id" : ObjectId("534009e4d852427820000002"), "building" : "22 A, Indiana Apt", "pincode" : 123456, "city" : "Los Angeles", "state" : "California" }
三、覆蓋索引查詢
覆蓋查詢是以下的查詢:
- 所有的查詢欄位是索引的一部分
- 所有的查詢返回欄位在同一個索引中
由於所有出現在查詢中的欄位是索引的一部分, MongoDB 無需在整個數據文檔中檢索匹配查詢條件和返回使用相同索引的查詢結果。因為索引存在於RAM中,從索引中獲取數據比通過掃描文檔讀取數據要快得多。
例:user集合:
{ "_id": ObjectId("53402597d852426020000002"), "contact": "987654321", "dob": "01-01-1991", "gender": "M", "name": "Tom Benzamin", "user_name": "tombenzamin" }
創建聯合索引,欄位為gender和user_name
db.users.ensureIndex({gender:1,user_name:1})
現在,該索引會覆蓋以下查詢:
db.users.find({gender:"M"},{user_name:1,_id:0})
對於上述查詢,MongoDB的不會去資料庫文件中查找。相反,它會從索引中提取數據,這是非常快速的數據查詢。由於我們的索引中不包括 _id 欄位,_id在查詢中會預設返回,我們可以在MongoDB的查詢結果集中排除它。下麵的實例沒有排除_id,查詢就不會被覆蓋:
db.users.find({gender:"M"},{user_name:1})
如果所有索引欄位是一個數組則不能使用覆蓋索引查詢,所有索引欄位是一個子文檔。