@@ -116,50 +116,139 @@ DBQuery.prototype.shellPrint = function(){
116116 var paranoia = mongo_hacker_config . index_paranoia ;
117117
118118 if ( typeof paranoia !== 'undefined' && paranoia ) {
119- var explain = this . clone ( ) ;
120- explain . _ensureSpecial ( ) ;
121- explain . _query . $explain = true ;
122- explain . _limit = Math . abs ( n ) * - 1 ;
123- var result = explain . next ( ) ;
124-
125- if ( current_version < 3 ) {
126- var type = result . cursor ;
127-
128- if ( type !== undefined ) {
129- var index_use = "Index[" ;
130- if ( type == "BasicCursor" ) {
131- index_use += colorize ( "none" , { color : "red" , bright : true } ) ;
119+ var explanation = this . explain ( ) ;
120+ var cursor = explanation . cursor ;
121+ var clauses = explanation . clauses ;
122+ var queryPlanner = explanation . queryPlanner ;
123+
124+ if ( cursor !== undefined || clauses !== undefined ) {
125+ var index_use = "Index[" ;
126+ var parseClause = function ( clause ) {
127+ var indexInfo ;
128+ if ( clause . cursor === "BasicCursor" ) {
129+ indexInfo = colorize ( "none" , { color : "red" , bright : true } ) ;
132130 } else {
133- index_use += colorize ( result . cursor . substring ( 12 ) , { color : "green" , bright : true } ) ;
131+ var indexName = clause . cursor === "IDCursor" ? "_id_" : clause . cursor . split ( " " ) [ 1 ] ;
132+ indexInfo = colorize ( indexName , { color : "green" , bright : true } ) ;
133+ if ( clause . indexOnly ) {
134+ indexInfo += colorize ( "(covered)" , { color : "green" , bright : false } ) ;
135+ }
136+ }
137+ return indexInfo ;
138+ } ;
139+ if ( clauses ) {
140+ var clauseInfo = [ ] ;
141+ var singleClauseInfo ;
142+ for ( var i = 0 , length = clauses . length ; i < length ; i ++ ) {
143+ singleClauseInfo = parseClause ( clauses [ i ] ) ;
144+ if ( clauseInfo . filter ( function ( info ) { return info === singleClauseInfo ; } ) . length === 0 ) {
145+ clauseInfo . push ( singleClauseInfo ) ;
146+ }
134147 }
135- index_use += "]" ;
136- output . push ( index_use ) ;
148+ index_use += clauseInfo . join ( ', ' ) ;
149+ } else {
150+ index_use += parseClause ( explanation ) ;
137151 }
138- } else {
139- var winningPlan = result . queryPlanner . winningPlan ;
140- var winningInputStage = winningPlan . inputStage . inputStage ;
141-
142- if ( winningPlan !== undefined ) {
143- var index_use = "Index[" ;
144- if ( winningPlan . inputStage . stage === "COLLSCAN" || ( winningInputStage !== undefined && winningInputStage . stage !== "IXSCAN" ) ) {
145- index_use += colorize ( "none" , { color : "red" , bright : true } ) ;
146- } else {
147- var fullScan = false ;
148- for ( index in winningInputStage . keyPattern ) {
149- if ( winningInputStage . indexBounds [ index ] [ 0 ] == "[MinKey, MaxKey]" ) {
150- fullScan = true ;
152+ index_use += "]" ;
153+ output . push ( index_use ) ;
154+ } else if ( queryPlanner !== undefined ) {
155+ var collectionIndexes ;
156+ var getIndexNameByKey = ( function ( query ) {
157+ return function ( key ) {
158+ if ( ! collectionIndexes ) {
159+ var nsParts = query . _ns . split ( '.' ) ;
160+ var dbName = nsParts [ 0 ] ;
161+ var colName = nsParts [ 1 ] ;
162+ collectionIndexes = db . getSisterDB ( dbName ) [ colName ] . getIndexes ( ) ;
163+ }
164+ return collectionIndexes . filter ( function ( index ) {
165+ return JSON . stringify ( index . key ) === JSON . stringify ( key ) ;
166+ } ) [ 0 ] . name ;
167+ }
168+ } ) ( this ) ;
169+ var traverseStageTree = function ( currentStage , results ) {
170+ results = results || {
171+ collscans : 0 ,
172+ eof : false ,
173+ fetches : 0 ,
174+ idhacks : 0 ,
175+ indexes : [ ] ,
176+ ixscans : 0
177+ } ;
178+ switch ( currentStage . stage ) {
179+ case "EOF" :
180+ results . eof = true ;
181+ break ;
182+ case "COLLSCAN" :
183+ results . collscans ++ ;
184+ break ;
185+ case "IDHACK" :
186+ results . idhacks ++ ;
187+ break ;
188+ case "IXSCAN" :
189+ results . ixscans ++ ;
190+ var currentIndexName = currentStage . indexName ;
191+ if ( ! currentIndexName ) {
192+ currentIndexName = getIndexNameByKey ( currentStage . keyPattern ) ;
193+ }
194+ if ( results . indexes . filter ( function ( indexName ) { return indexName === currentIndexName ; } ) . length === 0 ) {
195+ results . indexes . push ( currentIndexName ) ;
196+ }
197+ break ;
198+ case "FETCH" :
199+ results . fetches ++ ;
200+ // Fallthrough.
201+ default :
202+ if ( currentStage . inputStage ) {
203+ traverseStageTree ( currentStage . inputStage , results ) ;
204+ } else if ( currentStage . inputStages ) {
205+ for ( var i = 0 , length = currentStage . inputStages . length ; i < length ; i ++ ) {
206+ traverseStageTree ( currentStage . inputStages [ i ] , results ) ;
151207 }
152208 }
153-
154- if ( fullScan ) {
155- index_use += colorize ( winningInputStage . indexName + " (full scan)" , { color : "yellow" , bright : true } ) ;
156- } else {
157- index_use += colorize ( winningInputStage . indexName , { color : "green" , bright : true } ) ;
209+ }
210+ return results ;
211+ } ;
212+ var parseQueryResults = function ( results ) {
213+ var indexInfo ;
214+ if ( results . eof ) {
215+ indexInfo = colorize ( "collection doesn't exist" , { color : "red" , bright : true } ) ;
216+ } else if ( results . idhacks ) {
217+ indexInfo = colorize ( "_id_" , { color : "green" , bright : true } ) ;
218+ } else if ( results . ixscans ) {
219+ indexInfo = results . indexes . map ( function ( index ) {
220+ return colorize ( index , { color : "green" , bright : true } ) ;
221+ } ) . join ( ', ' ) ;
222+ if ( ! results . fetches ) {
223+ indexInfo += colorize ( " (covered)" , { color : "green" , bright : false } ) ;
158224 }
225+ } else if ( results . collscans ) {
226+ indexInfo = colorize ( "none" , { color : "red" , bright : true } ) ;
227+ } else {
228+ indexInfo = colorize ( "CAN'T DETERMINE" , { color : "red" , bright : true } ) ;
159229 }
160- index_use += "]" ;
161- output . push ( index_use ) ;
230+ return indexInfo ;
231+ } ;
232+
233+ var index_use = "Index[" ;
234+ if ( queryPlanner . winningPlan . shards ) {
235+ var shards = queryPlanner . winningPlan . shards ;
236+ var shardIndexesInfo = [ ] ;
237+ shards . forEach ( function ( shard ) {
238+ shardIndexesInfo . push (
239+ "shard " +
240+ colorize ( shard . shardName , { color : "blue" , bright : true } ) +
241+ ": " +
242+ parseQueryResults ( traverseStageTree ( shard . winningPlan ) )
243+ ) ;
244+ } ) ;
245+ index_use += shardIndexesInfo . join ( '; ' ) ;
246+ } else {
247+ index_use += parseQueryResults ( traverseStageTree ( queryPlanner . winningPlan ) ) ;
162248 }
249+
250+ index_use += "]" ;
251+ output . push ( index_use ) ;
163252 }
164253 }
165254
0 commit comments