mongodb-explain-plan-model
Advanced tools
Comparing version 0.1.3 to 0.2.0
189
lib/index.js
@@ -1,177 +0,20 @@ | ||
var Model = require('ampersand-model'); | ||
var assign = require('lodash.assign'); | ||
var set = require('lodash.set'); | ||
var each = require('lodash.foreach'); | ||
var Model = require('./model'); | ||
var LegacyModel = require('./legacy-model'); | ||
var stageIterationMixin = require('./stage-iteration'); | ||
// var debug = require('debug')('mongodb-explain-plan-model'); | ||
var ExplainPlanModel = Model.extend(stageIterationMixin, { | ||
extraProperties: 'ignore', | ||
props: { | ||
namespace: 'string', | ||
parsedQuery: 'object', | ||
executionSuccess: 'boolean', | ||
nReturned: 'number', | ||
executionTimeMillis: 'number', | ||
totalKeysExamined: 'number', | ||
totalDocsExamined: 'number', | ||
rawExplainObject: 'object', | ||
legacyMode: { | ||
type: 'boolean', // true if ingested from 2.6 or before version | ||
required: true, | ||
default: false | ||
} | ||
}, | ||
session: { | ||
initialized: { | ||
type: 'boolean', | ||
default: false | ||
} | ||
}, | ||
derived: { | ||
usedIndex: { | ||
deps: ['rawExplainObject', 'legacyMode'], | ||
fn: function() { | ||
if (this.legacyMode) { | ||
var mtch = this.rawExplainObject.cursor.match(/BTreeCursor (\S+)$/); | ||
return mtch ? mtch[1] : null; | ||
} | ||
var ixscan = this.findStageByName('IXSCAN'); | ||
if (ixscan) { | ||
return ixscan.indexName; | ||
} | ||
// special case for IDHACK stage, using the _id_ index. | ||
var idhack = this.findStageByName('IDHACK'); | ||
return idhack ? '_id_' : null; | ||
} | ||
}, | ||
// https://docs.mongodb.org/manual/reference/explain-results/#covered-queries | ||
isCovered: { | ||
deps: ['rawExplainObject', 'legacyMode'], | ||
fn: function() { | ||
if (this.legacyMode) { | ||
return Boolean(this.rawExplainObject.indexOnly); | ||
} | ||
if (this.totalDocsExamined > 0) { | ||
return false; | ||
} | ||
var ixscan = this.findStageByName('IXSCAN'); | ||
if (!ixscan) { | ||
return false; | ||
} | ||
return !ixscan.parentName || ixscan.parentName !== 'FETCH'; | ||
} | ||
}, | ||
isMultiKey: { | ||
deps: ['rawExplainObject', 'legacyMode'], | ||
fn: function() { | ||
if (this.legacyMode) { | ||
return this.rawExplainObject.isMultiKey; | ||
} | ||
var ixscan = this.findStageByName('IXSCAN'); | ||
return Boolean(ixscan && ixscan.isMultiKey); | ||
} | ||
}, | ||
// https://docs.mongodb.org/manual/reference/explain-results/#sort-stage | ||
inMemorySort: { | ||
deps: ['rawExplainObject', 'legacyMode'], | ||
fn: function() { | ||
if (this.legacyMode) { | ||
return this.rawExplainObject.scanAndOrder; | ||
} | ||
return this.findStageByName('SORT') !== null; | ||
} | ||
}, | ||
isCollectionScan: { | ||
deps: ['rawExplainObject', 'legacyMode'], | ||
fn: function() { | ||
if (this.legacyMode) { | ||
return this.rawExplainObject.cursor === 'BasicCursor'; | ||
} | ||
return this.findStageByName('COLLSCAN') !== null; | ||
} | ||
} | ||
}, | ||
/** | ||
* extracts basic information from older (2.6 and prior) explain plan | ||
* versions and transforms them into the shape of a 3.0+ explain output. | ||
* | ||
* @param {Object} attrs - legacy explain plan object | ||
* @return {Object} - new explain plan object | ||
*/ | ||
_mapLegacyFields: function(attrs) { | ||
var legacyMap = { | ||
n: 'nReturned', | ||
nscanned: 'totalKeysExamined', | ||
nscannedObjects: 'totalDocsExamined', | ||
millis: 'executionTimeMillis', | ||
indexOnly: 'coveredQuery' | ||
}; | ||
var result = {}; | ||
each(legacyMap, function(newVal, oldVal) { | ||
set(result, newVal, attrs[oldVal]); | ||
}); | ||
return result; | ||
}, | ||
/** | ||
* Walks the tree of execution stages from a given node (or root) and returns | ||
* the first stage with the specified name, or null if no stage is found. | ||
* Equally-named children stage are traversed and returned in order. | ||
* Returns null if legacyMode is true. | ||
* | ||
* @param {String} name - name of stage to return | ||
* @param {Object} root - stage to start from. If unspecified, start from | ||
* executionStages root node. | ||
* @return {Object|null} - stage object or null | ||
*/ | ||
findStageByName: function(name, root) { | ||
// not supported for legacy mode | ||
if (this.legacyMode) { | ||
return null; | ||
} | ||
var it = this._getStageIterator(root); | ||
for (var stage = it.next(); stage !== null; stage = it.next()) { | ||
if (stage.stage === name) { | ||
return stage; | ||
} | ||
} | ||
return null; | ||
}, | ||
/** | ||
* pre-process explain output to match the structure of this model. | ||
* | ||
* @param {Object} attrs - explain plan output | ||
* @return {Object} - transformed object to initialize this model | ||
*/ | ||
parse: function(attrs) { | ||
var result = {}; | ||
if (attrs.cursor) { | ||
// 2.6 or prior explain output, switch to legacy mode | ||
result.legacyMode = true; | ||
assign(result, this._mapLegacyFields(attrs)); | ||
} else { | ||
result.legacyMode = false; | ||
assign(result, attrs.queryPlanner); | ||
assign(result, attrs.executionStats); | ||
} | ||
// copy the original object into `rawExplainObject` | ||
result.rawExplainObject = JSON.parse(JSON.stringify(attrs)); | ||
result.initialized = true; | ||
return result; | ||
}, | ||
/** | ||
* serialize the model back into a plain javascript object. | ||
* | ||
* @return {Object} - plain javascript object of this model | ||
*/ | ||
serialize: function() { | ||
return this.getAttributes({ | ||
props: true, derived: true | ||
}); | ||
/** | ||
* Returns a model for current (3.0+) or legacy (2.6) explain plans. | ||
* | ||
* @param {object} explain the raw explain plan output as object | ||
* @return {Model} the matching model | ||
*/ | ||
function ExplainPlanModel(explain) { | ||
if (!explain) { | ||
return new Model(); | ||
} | ||
}); | ||
if (explain.cursor || explain.clusteredType) { | ||
return new LegacyModel(explain, {parse: true}); | ||
} | ||
return new Model(explain, {parse: true}); | ||
} | ||
module.exports = ExplainPlanModel; |
var each = require('lodash.foreach'); | ||
// var debug = require('debug')('mongodb-explain-plan-model:stage-iteration'); | ||
@@ -47,4 +48,4 @@ var stageIterationMixin = { | ||
* returns child stage or stages of current stage as array. If there are | ||
* no more child stages, returns empty array []. Not supported for legacy | ||
* mode. | ||
* no more child stages, returns empty array []. Also works for sharded | ||
* explain plans (where shards are children). Not supported for legacy mode. | ||
* | ||
@@ -60,3 +61,9 @@ * @param {Object} stage - stage to get children of. | ||
stage = stage || this.rawExplainObject.executionStats.executionStages; | ||
return stage.inputStage ? [stage.inputStage] : stage.inputStages; | ||
if (stage.inputStage) { | ||
return [stage.inputStage]; | ||
} | ||
if (stage.executionStages) { | ||
return [stage.executionStages]; | ||
} | ||
return stage.shards || stage.inputStages || []; | ||
}, | ||
@@ -73,3 +80,3 @@ /** | ||
var it = this._getStageIterator(root); | ||
for (var stage = it.next(); stage !== null; stage = it.next()) { | ||
for (var stage = it.next(); stage; stage = it.next()) { | ||
result.push(stage); | ||
@@ -76,0 +83,0 @@ } |
{ | ||
"name": "mongodb-explain-plan-model", | ||
"description": "Ampersand model abstraction for MongoDB explain plans (3.0+)", | ||
"version": "0.1.3", | ||
"version": "0.2.0", | ||
"scripts": { | ||
@@ -19,4 +19,8 @@ "fmt": "mongodb-js-fmt", | ||
"lodash.assign": "^4.0.8", | ||
"lodash.filter": "^4.4.0", | ||
"lodash.foreach": "^4.2.0", | ||
"lodash.map": "^4.4.0", | ||
"lodash.set": "^4.1.0", | ||
"lodash.some": "^4.4.0", | ||
"lodash.uniq": "^4.3.0", | ||
"lodash.zip": "^4.0.0" | ||
@@ -23,0 +27,0 @@ }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
26720
10
382
9
1
+ Addedlodash.filter@^4.4.0
+ Addedlodash.map@^4.4.0
+ Addedlodash.some@^4.4.0
+ Addedlodash.uniq@^4.3.0
+ Addedlodash.filter@4.6.0(transitive)
+ Addedlodash.map@4.6.0(transitive)
+ Addedlodash.some@4.6.0(transitive)
+ Addedlodash.uniq@4.5.0(transitive)