mongodb 關系、引用、覆蓋索引查詢


一、關系

  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})

  如果所有索引字段是一個數組則不能使用覆蓋索引查詢,所有索引字段是一個子文檔。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM