MongoDB進階-內嵌文檔查詢

做爲非關係型數據庫中的佼佼者,MongoDB一大優點在於可以在一條文檔中存儲對象類型的數據,適當增長冗餘來讓數據庫更好用。文檔中一個對象類型的字段在MongoDB中被稱爲內嵌文檔(Embedded),也是MongoDB推薦的存儲形式。本文將基於官方文檔介紹內嵌文檔的查詢方法。python

1.內嵌文檔的適用場景

對於初創企業的技術團隊來講,快速變更的需求致使沒有必要花費過多精力設計關係嚴格的數據表,而是能夠直接將相關聯的數據字段放在一塊兒,好比如下設計:web

db.books.insertMany( [
   { _id: 1, name: "python", price: 25, size: { h: 14, w: 21}, reading: ["Tom","John"] },
   { _id: 2, name: "mongo", price: 50, size: { h: 8.5, w: 11}, reading: ["John","Dave"] },
   { _id: 3, name: "webGL", price: 80, size: { h: 8.5, w: 11}, reading: ["Lily"] },
]);
複製代碼

若是使用相似關係型數據主鍵的將_id做爲引用的方式以下:數據庫

db.books.insertMany( [
   { _id: 1, name: "python", price: 25, h: 14,  w: 21, reading: ["Tom","John"] },
   { _id: 2, name: "mongo",  price: 50, h: 8.5, w: 11, reading: ["John","Dave"] },
   { _id: 3, name: "webGL",  price: 80, h: 8.5, w: 11, reading: ["Lily"] },
]);
 db.reading.insertMany( [
   { _id: 4, reader: "Tom",  book_id:1 },
   { _id: 5, reader: "John", book_id:1 },
   { _id: 6, reader: "John", book_id:2 },
   { _id: 7, reader: "Dave", book_id:2 },
   { _id: 8, reader: "Lily", book_id:3 },
]);
複製代碼

相比之下,內嵌的方式有如下優勢:bash

  1. 使用者查詢次數減小 能夠快速讀取到比較完整的相關信息
  2. 使用字典對象和列表對象增長字段和成員都格外方便

內嵌文檔能夠下降字段修改對調用者的影響,好比在size字段下增長一個名爲"l"的子字段表示書籍長度,對於調用者來講只須要在用到時從size對象中拿出來便可,不須要再去額外獲取新的字段。 所以,在內嵌文檔較小,更新頻率不高時推薦使用內嵌文檔來存儲數據。spa

2.內嵌文檔爲字典的查詢方法

以1中數據爲例,對於單值的字段查詢,只須要寫一個查詢字典(query filter)便可:設計

db.books.find( { price: 25 } );
複製代碼

當查詢條件涉及內嵌文檔中的子字段時,使用"."(可遞進使用):code

db.books.find( { "size.h": 8.5 } );//針對字典對象
 -->[
  { _id: 2, name: "mongo", price: 50, size: { h: 8.5, w: 11}, reading: ["John","Dave"] },
  { _id: 3, name: "webGL", price: 80, size: { h: 8.5, w: 11}, reading: ["Lily"] },
  ]
 db.books.find( { "reading.0": "Tom" } );//針對列表
 -->[
   { _id: 1, name: "python", price: 25, h: 14,  w: 21, reading: ["Tom","John"] },
  ]
複製代碼

注意,不使用"."的話將會嚴格匹配內嵌文檔:對象

db.books.find( { "size": { h: 8.5} } );//不存在size字段爲{ h: 8.5}的文檔
 -->[]
複製代碼

同普通查詢同樣,可使用運算符Query Operator文檔

db.books.find( { "size.w": { $lt: 21} } );
 -->[
  { _id: 2, name: "mongo", price: 50, size: { h: 8.5, w: 11}, reading: ["John","Dave"] },
  { _id: 3, name: "webGL", price: 80, size: { h: 8.5, w: 11}, reading: ["Lily"] },
  ]
複製代碼

3.內嵌文檔爲列表的查詢方法

示例數據string

db.books.insertMany( [
   { _id: 1, name: "python", price: 25, size: [14,21], reading: ["Tom","John"] },
   { _id: 2, name: "mongo", price: 50, size: [8.5,11], reading: ["John","Dave"] },
   { _id: 3, name: "webGL", price: 80, size: [8.5,11], reading: ["Lily"] },
]);
複製代碼

(1)指定列表{key:[value]} 列表必須符合value的條件

以1中數據爲例,指定列表,將嚴格按照全部元素及其順序查詢:

db.books.find( { reading: ["Tom","John"]" }); -->[ { _id: 1, name: "python", price: 25, size: size: [14,21], reading: ["Tom","John"] }, ] 複製代碼

若只要求指定元素存在且不要求順序,使用$all:

db.books.find( { reading: { $all: ["John"] } });
 -->[
  { _id: 1, name: "python", price: 25, size:[14,21], reading: ["Tom","John"] },
  { _id: 2, name: "mongo", price: 50,  size:[8.5,11], reading: ["John","Dave"] },
  ]
複製代碼

(2)指定元素{key:value1,value2...} 對於各個value的條件都至少有一個元素知足便可,不要求一個元素同時知足全部條件

db.books.find( { reading: "John" });//只要列表中有一元素的值爲"John"即知足
 -->[
  { _id: 1, name: "python", price: 25, size:[14,21], reading: ["Tom","John"] },
  { _id: 2, name: "mongo", price: 50,  size:[8.5,11], reading: ["John","Dave"] },
  ]
 db.books.find( { size: { $gt: 16, $lt: 15} });//只要列表中有一元素的值大於16,還有一元素小於15即知足
 -->[
  { _id: 1, name: "python", price: 25, size: [14,21], reading: ["Tom","John"] },
  ]
複製代碼

(3)指定元素{key:{$elemMatch:value1,value2...}} 只要至少有一元素同時符合各個value的條件

使用$elemMatch

db.books.find( { size: { $elemMatch: { $gt: 22, $lt: 30 } } });
 -->[
  { _id: 1, name: "python", price: 25, size: [14,21], reading: ["Tom","John"] },
  ]
複製代碼

(4)指定列表長度{key:{ $size: value... }}知足條件

使用$size

db.books.find( { reading: { $size: { $gt: 1} } });
 -->[
    { _id: 3, name: "webGL", price: 80, size: [8.5,11], reading: ["Lily"] },
  ]
複製代碼

總結,對於列表類型的內嵌文檔,$elemMatch給出的並列條件要求至少有一個元素同時知足,不使用elemMatch時並列的條件只須要各自至少有一個元素知足便可。

相關文章
相關標籤/搜索