這篇文章主要給大家介紹了關于MongoDB通配符索引的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
指南
MongoDB在4.2 版本推出了Wildcard Indexes,究竟什么是Wildcard Indexes以及Wildcard Indexes適合哪些場景本文結合官方文檔以及實際測試進行簡單概述。
1、通配符索引示例
因為MongoDB是dynamic schemas,所以應用是可以查詢任何已知字段或者隨機字段的。
假設(此假設案例摘自官方文檔),集合colA的UserMetadata字段包含如下數(shù)據(jù):
{ "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" })
是否能通過一個索引來完成上述需求?
答案是肯定的,上述查詢可以通過通配符索引來實現(xiàn)既定需求,也就是 db.colA.createIndex( { "userMetadata.$**" : 1 } )。
那么如何創(chuàng)建通配符索引?
注意: 首先應該明確的是通配符索引只在版本兼容性4.2的時候才能創(chuàng)建。
如何查詢版本兼容性?
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"
}
}
}
如果數(shù)據(jù)結構是上面這樣的,其中product_attributes 屬性包含任何的結構。
那么如果我們創(chuàng)建一個這個索引,它會進行什么操作?
db.product_catalog.createIndex({"product_attributes.$**":1})。
因為product_attributes 里面包含數(shù)組和嵌套文檔等對象,實際創(chuàng)建這個索引后,會迭代嵌套文檔或者數(shù)組把里面的所有的值都取出來放到索引里。支持如下查詢:
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}})
全字段的通配符索引
可以通過下面的語句創(chuàng)建一個索引,索引中包含集合中的所有字段,但是不包括_id(如果想包含_id可以通過wildcardProjection 來設置),如果集合中的字段包含數(shù)組或者嵌套對象的話,那么會迭代數(shù)組或者嵌套對象并把值放到索引中。
Db.product_catalog.createIndex({“$**”:1})
給每個文檔添加一個address的字段。
7777:PRIMARY> db.product_catalog.find().pretty()
{
"_id" : ObjectId("5ee2df16911d8dfaa91520b4"),
"product_name" : "Spy Coat",
"product_attributes" : {
"material" : [
"Tweed",
"Wool",
"Leather"
],
"size" : {
"length" : 72,
"units" : "inches"
}
},
"address" : "Beijing"
}
{
"_id" : ObjectId("5ee2df30911d8dfaa91520b5"),
"product_name" : "Spy Pen",
"product_attributes" : {
"colors" : [
"Blue",
"Black"
],
"secret_feature" : {
"name" : "laser",
"power" : "1000",
"units" : "watts"
}
},
"address" : "Tianjin"
}
db.product_catalog.find({"product_name":"Spy Coat","address":"nanji","product_attributes.colors":"Blue"})
在全字段通配符索引的基礎上可以明確包含哪些或者不包含哪些字段到通配符索引中,只能是在全字段通配符索引的基礎上,單字段的是不可以的:
在全字段的基礎上創(chuàng)建一個明確包含哪些字段的索引:
db.collection.createIndex(
{ "$**" : 1 },
{ "wildcardProjection" :
{ "fieldA" : 1, "fieldB.fieldC" : 1 }
}
)
注意:通配符索引不支持在使用wildcardProjection的時候混合使用包含和排除語句,除了明確指定包含_id字段的時候。
在全字段的基礎上創(chuàng)建一個明確不包含哪些字段的索引:
db.collection.createIndex(
{ "$**" : 1 },
{ "wildcardProjection" :
{ "fieldA" : 0, "fieldB.fieldC" : 0 }
}
)
3、通配符索引的行為
通配符索引的行為根據(jù)其字段類型不同而有所不同。
字段為對象
如果是對象的話,會將對象中的內容存儲到索引中,通配符索引會把對象中的所有嵌套對象加載到索引中。
字段為數(shù)組
如果是數(shù)組的話,通配符索引遍歷數(shù)組并且將每個元素都存儲到索引中。
如果數(shù)組中的元素是一個對象的話,通配符索引把對象中的內容加載到索引中,像上面的加載對象一樣。
如果數(shù)組中的元素是一個數(shù)組的話(就是多維數(shù)組),通配符索引并不迭代嵌套數(shù)組,相反是把整個嵌套數(shù)組作為一個值來看。
其他類型
把值記錄到數(shù)組中。
通配符索引會持續(xù)迭代任何的嵌套對象或者數(shù)組直到最底層(就是不能在迭代為止),然后它會索引全路徑。
通配符索引對于顯示數(shù)組位置的查詢
通配符索引雖然不會記錄給定數(shù)組中的元素下標,但是,MongoDB仍然可以選擇通配符索引來滿足包含一個或多個顯式數(shù)組索引的字段路徑的查詢(for example, parentArray.0.nestedArray.0)
由于為每個連續(xù)嵌套數(shù)組定義索引邊界的復雜性日益增加,如果該路徑包含8個以上的顯式數(shù)組索引,MongoDB不會考慮使用通配符索引來回答查詢中的給定字段路徑。MongoDB仍然可以考慮使用通配符索引來回答查詢中的其他字段路徑。
如果超過了8個以上顯示數(shù)組索引的話MongoDB 會考慮另外的索引或者執(zhí)行全集合掃描。如下結構:
{
"parentObject" : {
"nestedArray" : [
"elementOne",
{
"deeplyNestedArray" : [ "elementTwo" ]
}
]
}
}
請注意,通配符索引本身對索引文檔時遍歷文檔的深度沒有任何限制;該限制僅適用于顯式指定精確數(shù)組索引的查詢。通過發(fā)出沒有顯式數(shù)組索引的相同查詢,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.通配符索引不支持直接等于/不等于一個對象或者數(shù)組。
通配符索引會將對象或者數(shù)組中的元素加載到索引中,而不是整體放到索引中。故通配符索引不支持直接用文檔或者數(shù)組來匹配。
所以上面的例子如果
7777:PRIMARY> db.test_new_wildidx.find({"block.attr.address_new": ["haicheng", "beijing", "chongqing"]})
就是想匹配整個數(shù)組的話,是不可能用到通配符索引的。
那么如果有這個需求該如何解決?Db.test_new_wildidx.createIndex({"block.attr.address_new":1}) 通過這個索引來解決。
雖然通配符索引不支持整個文檔或者對象直接精準匹配查詢,但是支持數(shù)組或者對象為空{} 這種操作:
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.通配符索引不支持文檔中的數(shù)組$ne null這種。其實不光是數(shù)組,別的字段也同樣,只要是$ne都不會使用通配符索引。
5、總結
通配符索引在一定程度上可以應對在建模初期對于索引建立疏忽的遺漏,但是如果一味依賴通配符索引來解決查詢中的各種精確字段的匹配那就是鄭人買履了,在實際測試中通配符索引和精確字段的索引相比隨著數(shù)據(jù)的增長效率逐漸下滑。這也是官方不是很建議使用通配符索引來替代常規(guī)索引的原因。
本文來自腳本之家,原文鏈接:https://www.jb51.net/article/195111.htm
申請創(chuàng)業(yè)報道,分享創(chuàng)業(yè)好點子。點擊此處,共同探討創(chuàng)業(yè)新機遇!