Mongodb通配符索引簽名和使用限制問題記錄
學(xué)習(xí)mongodb,體會mongodb的每一個使用細(xì)節(jié),歡迎閱讀威贊的文章。這是威贊發(fā)布的第98篇mongodb技術(shù)文章,歡迎瀏覽本專欄威贊發(fā)布的其他文章。如果您認(rèn)為我的文章對您有幫助或者解決您的問題,歡迎在文章下面點個贊,或者關(guān)注威贊。謝謝。威贊文章都是結(jié)合官方文檔,翻譯整理而來,并對每個知識點的描述都認(rèn)真思考和實踐,對難以理解的地方,使用簡單容易理解的方式進(jìn)行闡述。
Mongodb的通配符索引,為靈活的數(shù)據(jù)結(jié)構(gòu),提供了便利,但使用上有哪些限制?本文結(jié)合Mongodb的官方文檔,總結(jié)了Mongodb通配符索引的使用和限制。
索引簽名
自Mongodb5.0開始,通配符索引的wildcardProjection也會被包含到索引簽名當(dāng)中。索引簽名,是識別索引唯一性的標(biāo)志,包含了構(gòu)建索引的各種參數(shù)。將通配符索引的wildcardProjection包含到索引當(dāng)中,用戶可以建立帶有相同索引鍵但wildcardProjection不同的索引。如為集合books創(chuàng)建兩個通配符索引。
db.books.createIndex({"$**": 1},{ wildcardProjection: { "author.name": 1, "author.website": 1 }, name: "authorWildcard" }) db.books.createIndex({"$**": 1},{ wildcardProjection: { "publisher.name": 1 }, name: "publisherWildcard" })
查看索引
db.books.getIndexes() [ { "v": 2, "key": { "_id": 1 }, "name": "_id_" }, { "v": 2, "key": { "$**": 1 }, "name": "authorWildcard", "wildcardProjection": { "author.name": 1, "author.website": 1 } }, { "v": 2, "key": { "$**": 1 }, "name": "publisherWildcard", "wildcardProjection": { "publisher.name": 1 } } ]
兩個索引都創(chuàng)建成功
通配符索引限制
復(fù)合通配符索引限制 一個復(fù)合通配符索引只能包含一個通配符表達(dá)式,使用下面的表達(dá)式構(gòu)建,是不可以的
{userID: 1, "object1.$**":1, "object2.$**":1}
- 復(fù)合通配符索引當(dāng)中,非通配符索引鍵不能使用多鍵索引鍵
- 使用wildcardProjection選項時,構(gòu)建索引的通配符只能時$**, 不能使用帶有特殊路徑的通配符表達(dá)式。下面的表達(dá)式是合法的
{ key: { "$**:1"}, name: "index_all_with_projection", wildcardProjection: { "someFields.name": 1, "otherFields.values": 1 } }
而帶有字段的路徑是不合法的
{ key: { "someFields.$**:1"}, name: "index_all_with_projection", wildcardProjection: { "someFields.name": 1, "otherFields.values": 1 } }
_id字段默認(rèn)沒有包含在通配符索引當(dāng)中,如果用戶構(gòu)建的通配符索引需要包含_id字段,使用wildcardProjection指定包含_id字段。
db.studentGrades.createIndex({"$**": 1}, { wildcardProjection: { "grades": 1, "_id": 1 } })
唯一索引和過期時間
添加通配符索引時,不可指定唯一索引或索引過期時間。
空間索引與哈希
不能將通配符索引與空間索引和哈希索引合并創(chuàng)建通配符索引。
分片數(shù)據(jù)集
不能將通配符索引用來分片鍵當(dāng)中。
通配符索引不支持的查詢
數(shù)組字段不等于空的查詢不支持
如在inventory集合中,字段production_attributes上構(gòu)建了通配符索引。該通配符索引不支持?jǐn)?shù)組字段的空值不等查詢。如下面的查詢,Mongodb編排查詢計劃時,不會使用通配符索引
db.inventory.find({$ne: ["product_attributes.tags", null]}) db.inventory.aggregate([ { $match: { $ne: ["product_attributes.tags", null]} } ])
針對嵌入式文檔和數(shù)組的精確查詢
在構(gòu)建通配符索引時,Mongodb將嵌入式文檔和數(shù)組進(jìn)行解析,將解析后的基本數(shù)據(jù)類型和其對應(yīng)的字段路徑加入到通配符索引當(dāng)中,而不是將嵌入式文檔和數(shù)組放入到通配符索引的結(jié)構(gòu)當(dāng)中。因此通配符索引,無法支持基于嵌入式文檔和數(shù)組的精確查詢。如針對inventory集合的查詢,Mongodb在編排查詢計劃時,不會選擇通配符索引。
db.inventory.find( { "product_attributes": {"price": 29.99} } ) db.inventory.find( { "product_attributes.tags": ["waterproof", "fireproof"] } )
當(dāng)然,通配符索引也不能夠支持到嵌入式文檔和數(shù)組的不等查詢。
判斷字段是否存在
通配符索引是稀疏的。當(dāng)通配符索引指定的字段值在文檔當(dāng)中不存在時,文檔數(shù)據(jù)不會加入到通配符索引當(dāng)中。因此通配符索引不支持帶有判斷字段是否存在的查詢。
如通配符索引不支持下面的幾個查詢
db.inventory.find( { "product_attributes": {$exists: false} } ) db.inventory.aggregate([ { $match: { "product_attributes": { $exists: false} } } ])
多字段查詢
MongoDB不能使用非通配符索引來支持查詢謂詞的一部分而使用通配符索引來支持另一部分。
MongoDB不能在同一個查詢中使用多個通配符索引來支持不同的謂詞。
在一個通配符索引可以支持多個查詢字段的情況下,MongoDB只能使用通配符索引來支持其中一個查詢字段。MongoDB會根據(jù)對應(yīng)的通配符索引路徑自動選擇通配符索引支持的字段。
db.inventory.find( { "product_attributes.price": {$gt: 20}, "product_attributes.material": "silk", "product_attributes.size": "large" } )
Mongodb通配符索引只能夠支持查詢條件中的一個條件。而選擇哪個條件來使用通配符索引則與通配符索引的路徑有關(guān)。
查看上面查詢的執(zhí)行計劃
{ "explainVersion": "2", "queryPlanner": { "namespace": "test.inventory", "indexFilterSet": false, "parsedQuery": { "$and": [ { "product_attributes.material": { "$eq": "silk" } }, { "product_attributes.size": { "$eq": "large" } }, { "product_attributes.price": { "$gt": 20 } } ] }, "queryHash": "03951C4C", "planCacheKey": "BC3202F5", "maxIndexedOrSolutionsReached": false, "maxIndexedAndSolutionsReached": false, "maxScansToExplodeReached": false, "winningPlan": { "queryPlan": { "stage": "FETCH", "planNodeId": 2, "filter": { "$and": [ { "product_attributes.price": { "$gt": 20 } }, { "product_attributes.size": { "$eq": "large" } } ] }, "inputStage": { "stage": "IXSCAN", "planNodeId": 1, "keyPattern": { "$_path": 1, "product_attributes.material": 1 }, "indexName": "product_attributes.$**_1", "isMultiKey": false, "multiKeyPaths": { "$_path": [], "product_attributes.material": [] }, "isUnique": false, "isSparse": true, "isPartial": false, "indexVersion": 2, "direction": "forward", "indexBounds": { "$_path": [ "[\"product_attributes.material\", \"product_attributes.material\"]" ], "product_attributes.material": [ "[\"silk\", \"silk\"]" ] } } }, "slotBasedPlan": { "slots": "$$RESULT=s11 env: { s14 = 20, s1 = TimeZoneDatabase(America/Argentina/La_Rioja...Asia/Ashkhabad) (timeZoneDB), s10 = {\"$_path\" : 1, \"product_attributes.material\" : 1}, s6 = KS(3C70726F647563745F617474726962757465732E6D6174657269616C003C73696C6B00FE04), s15 = \"large\", s3 = 1721879566202 (NOW), s2 = Nothing (SEARCH_META), s5 = KS(3C70726F647563745F617474726962757465732E6D6174657269616C003C73696C6B000104) }", "stages": "[2] filter {(traverseF(s13, lambda(l1.0) { traverseF(getField(l1.0, \"price\"), lambda(l2.0) { ((l2.0 > s14) ?: false) }, false) }, false) && traverseF(s13, lambda(l3.0) { traverseF(getField(l3.0, \"size\"), lambda(l4.0) { ((l4.0 == s15) ?: false) }, false) }, false))} \n[2] nlj inner [] [s4, s7, s8, s9, s10] \n left \n [1] cfilter {(exists(s5) && exists(s6))} \n [1] ixseek s5 s6 s9 s4 s7 s8 [] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" @\"product_attributes.$**_1\" true \n right \n [2] limit 1 \n [2] seek s4 s11 s12 s7 s8 s9 s10 [s13 = product_attributes] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" true false \n" } }, "rejectedPlans": [ { "queryPlan": { "stage": "FETCH", "planNodeId": 2, "filter": { "$and": [ { "product_attributes.material": { "$eq": "silk" } }, { "product_attributes.size": { "$eq": "large" } } ] }, "inputStage": { "stage": "IXSCAN", "planNodeId": 1, "keyPattern": { "$_path": 1, "product_attributes.price": 1 }, "indexName": "product_attributes.$**_1", "isMultiKey": false, "multiKeyPaths": { "$_path": [], "product_attributes.price": [] }, "isUnique": false, "isSparse": true, "isPartial": false, "indexVersion": 2, "direction": "forward", "indexBounds": { "$_path": [ "[\"product_attributes.price\", \"product_attributes.price\"]" ], "product_attributes.price": [ "(20, inf.0]" ] } } }, "slotBasedPlan": { "slots": "$$RESULT=s11 env: { s14 = \"silk\", s10 = {\"$_path\" : 1, \"product_attributes.price\" : 1}, s1 = TimeZoneDatabase(America/Argentina/La_Rioja...Asia/Ashkhabad) (timeZoneDB), s15 = \"large\", s6 = KS(3C70726F647563745F617474726962757465732E70726963650033FFFFFFFFFFFFFFFFFE04), s3 = 1721879566202 (NOW), s5 = KS(3C70726F647563745F617474726962757465732E7072696365002B28FE04), s2 = Nothing (SEARCH_META) }", "stages": "[2] filter {(traverseF(s13, lambda(l1.0) { traverseF(getField(l1.0, \"material\"), lambda(l2.0) { ((l2.0 == s14) ?: false) }, false) }, false) && traverseF(s13, lambda(l3.0) { traverseF(getField(l3.0, \"size\"), lambda(l4.0) { ((l4.0 == s15) ?: false) }, false) }, false))} \n[2] nlj inner [] [s4, s7, s8, s9, s10] \n left \n [1] cfilter {(exists(s5) && exists(s6))} \n [1] ixseek s5 s6 s9 s4 s7 s8 [] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" @\"product_attributes.$**_1\" true \n right \n [2] limit 1 \n [2] seek s4 s11 s12 s7 s8 s9 s10 [s13 = product_attributes] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" true false \n" } }, { "queryPlan": { "stage": "FETCH", "planNodeId": 2, "filter": { "$and": [ { "product_attributes.material": { "$eq": "silk" } }, { "product_attributes.price": { "$gt": 20 } } ] }, "inputStage": { "stage": "IXSCAN", "planNodeId": 1, "keyPattern": { "$_path": 1, "product_attributes.size": 1 }, "indexName": "product_attributes.$**_1", "isMultiKey": false, "multiKeyPaths": { "$_path": [], "product_attributes.size": [] }, "isUnique": false, "isSparse": true, "isPartial": false, "indexVersion": 2, "direction": "forward", "indexBounds": { "$_path": [ "[\"product_attributes.size\", \"product_attributes.size\"]" ], "product_attributes.size": [ "[\"large\", \"large\"]" ] } } }, "slotBasedPlan": { "slots": "$$RESULT=s11 env: { s14 = \"silk\", s10 = {\"$_path\" : 1, \"product_attributes.size\" : 1}, s1 = TimeZoneDatabase(America/Argentina/La_Rioja...Asia/Ashkhabad) (timeZoneDB), s15 = 20, s6 = KS(3C70726F647563745F617474726962757465732E73697A65003C6C6172676500FE04), s3 = 1721879566202 (NOW), s5 = KS(3C70726F647563745F617474726962757465732E73697A65003C6C61726765000104), s2 = Nothing (SEARCH_META) }", "stages": "[2] filter {(traverseF(s13, lambda(l1.0) { traverseF(getField(l1.0, \"material\"), lambda(l2.0) { ((l2.0 == s14) ?: false) }, false) }, false) && traverseF(s13, lambda(l3.0) { traverseF(getField(l3.0, \"price\"), lambda(l4.0) { ((l4.0 > s15) ?: false) }, false) }, false))} \n[2] nlj inner [] [s4, s7, s8, s9, s10] \n left \n [1] cfilter {(exists(s5) && exists(s6))} \n [1] ixseek s5 s6 s9 s4 s7 s8 [] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" @\"product_attributes.$**_1\" true \n right \n [2] limit 1 \n [2] seek s4 s11 s12 s7 s8 s9 s10 [s13 = product_attributes] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" true false \n" } } ] }, "command": { "find": "inventory", "filter": { "product_attributes.price": { "$gt": 20 }, "product_attributes.material": "silk", "product_attributes.size": "large" }, "$db": "test" }, "serverInfo": { "host": "TEST-W11", "port": 27017, "version": "7.0.4", "gitVersion": "38f3e37057a43d2e9f41a39142681a76062d582e" }, "serverParameters": { "internalQueryFacetBufferSizeBytes": 104857600, "internalQueryFacetMaxOutputDocSizeBytes": 104857600, "internalLookupStageIntermediateDocumentMaxSizeBytes": 104857600, "internalDocumentSourceGroupMaxMemoryBytes": 104857600, "internalQueryMaxBlockingSortMemoryUsageBytes": 104857600, "internalQueryProhibitBlockingMergeOnMongoS": 0, "internalQueryMaxAddToSetBytes": 104857600, "internalDocumentSourceSetWindowFieldsMaxMemoryBytes": 104857600, "internalQueryFrameworkControl": "trySbeEngine" }, "ok": 1 }
查詢排序
通配符查詢僅支持索引覆蓋查詢的排序。排序字段還不能是數(shù)組。
如在集合product的product_attributes構(gòu)建通配符索引
db.products.createIndex({"product_attributes.$**": 1})
當(dāng)price字段不是數(shù)組時,通配符索引可以支持該排序查詢
db.products.find( {"product_attributes.price": { $gt: 10.00}} ).sort({"product_attributes.price": 1} )
到此這篇關(guān)于Mongodb通配符索引簽名和使用限制的文章就介紹到這了,更多相關(guān)Mongodb索引使用限制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決MongoDB6.0報錯:"mongo"不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件
這篇文章主要給大家介紹了關(guān)于解決MongoDB6.0報錯:"mongo"不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05MongoDB數(shù)據(jù)庫的特色和優(yōu)點介紹
這篇文章主要介紹了MongoDB數(shù)據(jù)庫的特色和優(yōu)點介紹,本文總結(jié)了每個開發(fā)人員都應(yīng)該知道的5個MongoDB特點,需要的朋友可以參考下2015-05-05Windows系統(tǒng)下安裝Mongodb 3.2.x的步驟詳解
mongodb3.x版本有好多新功能,關(guān)于這方面參考官網(wǎng)即可,下面這篇文章主要給大家介紹了在Windows系統(tǒng)下安裝Mongodb 3.2.x的詳細(xì)步驟,文中介紹的非常詳細(xì),需要的朋友們可以參考學(xué)習(xí),下面來一起看看吧。2017-03-03MongoDB系列教程(三):Windows中下載和安裝MongoDB
這篇文章主要介紹了MongoDB系列教程(三):MongoDB下載和安裝,本文講解使用Windows環(huán)境安裝MongoDB,需要的朋友可以參考下2015-05-05MongoDB數(shù)據(jù)去重與保存最新數(shù)據(jù)操作指南
在 MongoDB 數(shù)據(jù)庫中,我們經(jīng)常需要進(jìn)行數(shù)據(jù)去重并保留最新的數(shù)據(jù),本文將介紹如何使用 MongoDB 聚合操作完成這一任務(wù),并將結(jié)果保存到新的集合或者覆蓋原有的集合,感興趣的小伙伴跟著小編一起來看看吧2024-01-01