map_reduce.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.MapReduceOperation = void 0;
  4. const bson_1 = require("../bson");
  5. const db_1 = require("../db");
  6. const error_1 = require("../error");
  7. const read_preference_1 = require("../read_preference");
  8. const utils_1 = require("../utils");
  9. const command_1 = require("./command");
  10. const operation_1 = require("./operation");
  11. const exclusionList = [
  12. 'explain',
  13. 'readPreference',
  14. 'readConcern',
  15. 'session',
  16. 'bypassDocumentValidation',
  17. 'writeConcern',
  18. 'raw',
  19. 'fieldsAsRaw',
  20. 'promoteLongs',
  21. 'promoteValues',
  22. 'promoteBuffers',
  23. 'bsonRegExp',
  24. 'serializeFunctions',
  25. 'ignoreUndefined',
  26. 'enableUtf8Validation',
  27. 'scope' // this option is reformatted thus exclude the original
  28. ];
  29. /**
  30. * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection.
  31. * @internal
  32. */
  33. class MapReduceOperation extends command_1.CommandOperation {
  34. /**
  35. * Constructs a MapReduce operation.
  36. *
  37. * @param collection - Collection instance.
  38. * @param map - The mapping function.
  39. * @param reduce - The reduce function.
  40. * @param options - Optional settings. See Collection.prototype.mapReduce for a list of options.
  41. */
  42. constructor(collection, map, reduce, options) {
  43. super(collection, options);
  44. this.options = options !== null && options !== void 0 ? options : {};
  45. this.collection = collection;
  46. this.map = map;
  47. this.reduce = reduce;
  48. }
  49. execute(server, session, callback) {
  50. const coll = this.collection;
  51. const map = this.map;
  52. const reduce = this.reduce;
  53. let options = this.options;
  54. const mapCommandHash = {
  55. mapReduce: coll.collectionName,
  56. map: map,
  57. reduce: reduce
  58. };
  59. if (options.scope) {
  60. mapCommandHash.scope = processScope(options.scope);
  61. }
  62. // Add any other options passed in
  63. for (const n in options) {
  64. // Only include if not in exclusion list
  65. if (exclusionList.indexOf(n) === -1) {
  66. mapCommandHash[n] = options[n];
  67. }
  68. }
  69. options = Object.assign({}, options);
  70. // If we have a read preference and inline is not set as output fail hard
  71. if (this.readPreference.mode === read_preference_1.ReadPreferenceMode.primary &&
  72. options.out &&
  73. options.out.inline !== 1 &&
  74. options.out !== 'inline') {
  75. // Force readPreference to primary
  76. options.readPreference = read_preference_1.ReadPreference.primary;
  77. // Decorate command with writeConcern if supported
  78. (0, utils_1.applyWriteConcern)(mapCommandHash, { db: coll.s.db, collection: coll }, options);
  79. }
  80. else {
  81. (0, utils_1.decorateWithReadConcern)(mapCommandHash, coll, options);
  82. }
  83. // Is bypassDocumentValidation specified
  84. if (options.bypassDocumentValidation === true) {
  85. mapCommandHash.bypassDocumentValidation = options.bypassDocumentValidation;
  86. }
  87. // Have we specified collation
  88. try {
  89. (0, utils_1.decorateWithCollation)(mapCommandHash, coll, options);
  90. }
  91. catch (err) {
  92. return callback(err);
  93. }
  94. if (this.explain && (0, utils_1.maxWireVersion)(server) < 9) {
  95. callback(new error_1.MongoCompatibilityError(`Server ${server.name} does not support explain on mapReduce`));
  96. return;
  97. }
  98. // Execute command
  99. super.executeCommand(server, session, mapCommandHash, (err, result) => {
  100. if (err)
  101. return callback(err);
  102. // Check if we have an error
  103. if (1 !== result.ok || result.err || result.errmsg) {
  104. return callback(new error_1.MongoServerError(result));
  105. }
  106. // If an explain option was executed, don't process the server results
  107. if (this.explain)
  108. return callback(undefined, result);
  109. // Create statistics value
  110. const stats = {};
  111. if (result.timeMillis)
  112. stats['processtime'] = result.timeMillis;
  113. if (result.counts)
  114. stats['counts'] = result.counts;
  115. if (result.timing)
  116. stats['timing'] = result.timing;
  117. // invoked with inline?
  118. if (result.results) {
  119. // If we wish for no verbosity
  120. if (options['verbose'] == null || !options['verbose']) {
  121. return callback(undefined, result.results);
  122. }
  123. return callback(undefined, { results: result.results, stats: stats });
  124. }
  125. // The returned collection
  126. let collection = null;
  127. // If we have an object it's a different db
  128. if (result.result != null && typeof result.result === 'object') {
  129. const doc = result.result;
  130. // Return a collection from another db
  131. collection = new db_1.Db(coll.s.db.s.client, doc.db, coll.s.db.s.options).collection(doc.collection);
  132. }
  133. else {
  134. // Create a collection object that wraps the result collection
  135. collection = coll.s.db.collection(result.result);
  136. }
  137. // If we wish for no verbosity
  138. if (options['verbose'] == null || !options['verbose']) {
  139. return callback(err, collection);
  140. }
  141. // Return stats as third set of values
  142. callback(err, { collection, stats });
  143. });
  144. }
  145. }
  146. exports.MapReduceOperation = MapReduceOperation;
  147. /** Functions that are passed as scope args must be converted to Code instances. */
  148. function processScope(scope) {
  149. if (!(0, utils_1.isObject)(scope) || scope._bsontype === 'ObjectID') {
  150. return scope;
  151. }
  152. const newScope = {};
  153. for (const key of Object.keys(scope)) {
  154. if ('function' === typeof scope[key]) {
  155. newScope[key] = new bson_1.Code(String(scope[key]));
  156. }
  157. else if (scope[key]._bsontype === 'Code') {
  158. newScope[key] = scope[key];
  159. }
  160. else {
  161. newScope[key] = processScope(scope[key]);
  162. }
  163. }
  164. return newScope;
  165. }
  166. (0, operation_1.defineAspects)(MapReduceOperation, [operation_1.Aspect.EXPLAINABLE]);
  167. //# sourceMappingURL=map_reduce.js.map