1. 程式人生 > 資料庫 >MongoDB萬用字元索引的用法例項

MongoDB萬用字元索引的用法例項

指南

MongoDB在4.2 版本推出了Wildcard Indexes,究竟什麼是Wildcard Indexes以及Wildcard Indexes適合哪些場景本文結合官方文件以及實際測試進行簡單概述。

1、萬用字元索引示例

因為MongoDB是dynamic schemas,所以應用是可以查詢任何已知欄位或者隨機欄位的。

假設(此假設案例摘自官方文件),集合colA的UserMetadata欄位包含如下資料:

{ "userMetadata" : { "likes" : [ "dogs","cats" ] } }
{ "userMetadata" : { "dislikes" : "pickles" } }
{ "userMetadata" : { "age" : 45 } }
{ "userMetadata" : "inactive" }

但是在查詢的時候可能是如下語句:

db.colA.find({ "userMeta2
萬用字元索引的形式data.likes" : "dogs" })
db.colA.find({ "userMetadata.dislikes" : "pickles" })
db.colA.find({ "userMetadata.age" : { $gt : 30 } })
db.colA.find({ "userMetadata" : "inactive" })

是否能通過一個索引來完成上述需求?

答案是肯定的,上述查詢可以通過萬用字元索引來實現既定需求,也就是 db.colA.createIndex( { "userMetadata.$**" : 1 } )。

那麼如何建立萬用字元索引?

注意:首先應該明確的是萬用字元索引只在版本相容性4.2的時候才能建立。

如何查詢版本相容性?

db.adminCommand( { getParameter: 1,featureCompatibilityVersion: 1 } )

如何設定?

db.adminCommand( { setFeatureCompatibilityVersion: "4.2" } )

2、萬用字元索引的形式

單欄位萬用字元索引

{
 "_id" : ObjectId("5ee2df16911d8dfaa91520b4"),"product_name" : "Spy Coat","product_attributes" : {
 "material" : [
  "Tweed","Wool","Leather"
 ],"size" : {
  "length" : 72,"units" : "inches"
 }
 }
}
{
 "_id" : ObjectId("5ee2df30911d8dfaa91520b5"),"product_name" : "Spy Pen","product_attributes" : {
 "colors" : [
  "Blue","Black"
 ],"secret_feature" : {
  "name" : "laser","power" : "1000","units" : "watts"
 }
 }
}

如果資料結構是上面這樣的,其中product_attributes 屬性包含任何的結構。

那麼如果我們建立一個這個索引,它會進行什麼操作?

db.product_catalog.createIndex({"product_attributes.$**":1})。

因為product_attributes 裡面包含陣列和巢狀文件等物件,實際建立這個索引後,會迭代巢狀文件或者陣列把裡面的所有的值都取出來放到索引裡。支援如下查詢:

db.product_catalog.find({"product_attributes.colors":"Blue"})
db.product_catalog.find({"product_attributes.secret_feature.name":"laser"})
db.product_catalog.find({"product_attributes.size.length":{$gt:60}})

全欄位的萬用字元索引

可以通過下面的語句建立一個索引,索引中包含集合中的所有欄位,但是不包括_id(如果想包含_id可以通過wildcardProjection 來設定),如果集合中的欄位包含陣列或者巢狀物件的話,那麼會迭代陣列或者巢狀物件並把值放到索引中。

Db.product_catalog.createIndex({“$**”:1}) 

給每個文件新增一個address的欄位。

7777:PRIMARY> db.product_catalog.find().pretty()
{
 "_id" : ObjectId("5ee2df16911d8dfaa91520b4"),"units" : "inches"
 }
 },"address" : "Beijing"
}
{
 "_id" : ObjectId("5ee2df30911d8dfaa91520b5"),"units" : "watts"
 }
 },"address" : "Tianjin"
}

db.product_catalog.find({"product_name":"Spy Coat","address":"nanji","product_attributes.colors":"Blue"})

在全欄位萬用字元索引的基礎上可以明確包含哪些或者不包含哪些欄位到萬用字元索引中,只能是在全欄位萬用字元索引的基礎上,單欄位的是不可以的:

在全欄位的基礎上建立一個明確包含哪些欄位的索引:

db.collection.createIndex(
 { "$**" : 1 },{ "wildcardProjection" :
 { "fieldA" : 1,"fieldB.fieldC" : 1 }
 }
)

注意:萬用字元索引不支援在使用wildcardProjection的時候混合使用包含和排除語句,除了明確指定包含_id欄位的時候。

在全欄位的基礎上建立一個明確不包含哪些欄位的索引:

db.collection.createIndex(
 { "$**" : 1 },{ "wildcardProjection" :
 { "fieldA" : 0,"fieldB.fieldC" : 0 }
 }
)

3、萬用字元索引的行為

萬用字元索引的行為根據其欄位型別不同而有所不同。

  • 欄位為物件
    如果是物件的話,會將物件中的內容儲存到索引中,萬用字元索引會把物件中的所有巢狀物件載入到索引中。
  • 欄位為陣列
    如果是陣列的話,萬用字元索引遍歷陣列並且將每個元素都儲存到索引中。
    如果陣列中的元素是一個物件的話,萬用字元索引把物件中的內容載入到索引中,像上面的載入物件一樣。
    如果陣列中的元素是一個數組的話(就是多維陣列),萬用字元索引並不迭代巢狀陣列,相反是把整個巢狀陣列作為一個值來看。
  • 其他型別
    把值記錄到陣列中。
    萬用字元索引會持續迭代任何的巢狀物件或者陣列直到最底層(就是不能在迭代為止),然後它會索引全路徑。

萬用字元索引對於顯示陣列位置的查詢

萬用字元索引雖然不會記錄給定陣列中的元素下標,但是,MongoDB仍然可以選擇萬用字元索引來滿足包含一個或多個顯式陣列索引的欄位路徑的查詢(for example,parentArray.0.nestedArray.0)

由於為每個連續巢狀陣列定義索引邊界的複雜性日益增加,如果該路徑包含8個以上的顯式陣列索引,MongoDB不會考慮使用萬用字元索引來回答查詢中的給定欄位路徑。MongoDB仍然可以考慮使用萬用字元索引來回答查詢中的其他欄位路徑。

如果超過了8個以上顯示陣列索引的話MongoDB 會考慮另外的索引或者執行全集合掃描。如下結構:

{
 "parentObject" : {
 "nestedArray" : [
  "elementOne",{
   "deeplyNestedArray" : [ "elementTwo" ]
  }
  ]
 }
}

請注意,萬用字元索引本身對索引文件時遍歷文件的深度沒有任何限制;該限制僅適用於顯式指定精確陣列索引的查詢。通過發出沒有顯式陣列索引的相同查詢,MongoDB可以選擇萬用字元索引來回答查詢。

4、萬用字元索引的限制

1.首先萬用字元索引是一個稀疏索引,只存放存在的欄位在索引裡面,不存在的不存放,也就是說當你使用{$exists:false}的時候,是不會走索引的,是全集合掃描。

db.test_new_wildidx.find({"block.attr":{$exists:false}})

db.test_new_wildidx.find({"block.attr":{$exists:true}}) 但是支援true的。

2.萬用字元索引不支援直接等於/不等於一個物件或者陣列。

萬用字元索引會將物件或者陣列中的元素載入到索引中,而不是整體放到索引中。故萬用字元索引不支援直接用文件或者陣列來匹配。

所以上面的例子如果

7777:PRIMARY> db.test_new_wildidx.find({"block.attr.address_new": ["haicheng","beijing","chongqing"]})

就是想匹配整個陣列的話,是不可能用到萬用字元索引的。

那麼如果有這個需求該如何解決?Db.test_new_wildidx.createIndex({"block.attr.address_new":1}) 通過這個索引來解決。

雖然萬用字元索引不支援整個文件或者物件直接精準匹配查詢,但是支援陣列或者物件為空{} 這種操作:

7777:PRIMARY> db.test_new_wildidx.find({"block.attr": {}})
7777:PRIMARY> db.test_new_wildidx.find({"block.attr.address_new": {}})

3. 萬用字元索引支援如下索引型別或者或者屬性:

Compound
TTL
Text
2d (Geospatial)
2dsphere (Geospatial)
Hashed
Unique

4.萬用字元索引不支援文件中的陣列$ne null這種。其實不光是陣列,別的欄位也同樣,只要是$ne都不會使用萬用字元索引。

5、總結

萬用字元索引在一定程度上可以應對在建模初期對於索引建立疏忽的遺漏,但是如果一味依賴萬用字元索引來解決查詢中的各種精確欄位的匹配那就是鄭人買履了,在實際測試中萬用字元索引和精確欄位的索引相比隨著資料的增長效率逐漸下滑。這也是官方不是很建議使用萬用字元索引來替代常規索引的原因。

到此這篇關於MongoDB萬用字元索引的文章就介紹到這了,更多相關MongoDB萬用字元索引內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!