getIndexes.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. 'use strict';
  2. const get = require('../get');
  3. const helperIsObject = require('../isObject');
  4. const decorateDiscriminatorIndexOptions = require('../indexes/decorateDiscriminatorIndexOptions');
  5. /*!
  6. * Gather all indexes defined in the schema, including single nested,
  7. * document arrays, and embedded discriminators.
  8. */
  9. module.exports = function getIndexes(schema) {
  10. let indexes = [];
  11. const schemaStack = new WeakMap();
  12. const indexTypes = schema.constructor.indexTypes;
  13. const indexByName = new Map();
  14. collectIndexes(schema);
  15. return indexes;
  16. function collectIndexes(schema, prefix, baseSchema) {
  17. // Ignore infinitely nested schemas, if we've already seen this schema
  18. // along this path there must be a cycle
  19. if (schemaStack.has(schema)) {
  20. return;
  21. }
  22. schemaStack.set(schema, true);
  23. prefix = prefix || '';
  24. const keys = Object.keys(schema.paths);
  25. for (const key of keys) {
  26. const path = schema.paths[key];
  27. if (baseSchema != null && baseSchema.paths[key]) {
  28. // If looking at an embedded discriminator schema, don't look at paths
  29. // that the
  30. continue;
  31. }
  32. if (path.$isMongooseDocumentArray || path.$isSingleNested) {
  33. if (get(path, 'options.excludeIndexes') !== true &&
  34. get(path, 'schemaOptions.excludeIndexes') !== true &&
  35. get(path, 'schema.options.excludeIndexes') !== true) {
  36. collectIndexes(path.schema, prefix + key + '.');
  37. }
  38. if (path.schema.discriminators != null) {
  39. const discriminators = path.schema.discriminators;
  40. const discriminatorKeys = Object.keys(discriminators);
  41. for (const discriminatorKey of discriminatorKeys) {
  42. collectIndexes(discriminators[discriminatorKey],
  43. prefix + key + '.', path.schema);
  44. }
  45. }
  46. // Retained to minimize risk of backwards breaking changes due to
  47. // gh-6113
  48. if (path.$isMongooseDocumentArray) {
  49. continue;
  50. }
  51. }
  52. const index = path._index || (path.caster && path.caster._index);
  53. if (index !== false && index !== null && index !== undefined) {
  54. const field = {};
  55. const isObject = helperIsObject(index);
  56. const options = isObject ? index : {};
  57. const type = typeof index === 'string' ? index :
  58. isObject ? index.type :
  59. false;
  60. if (type && indexTypes.indexOf(type) !== -1) {
  61. field[prefix + key] = type;
  62. } else if (options.text) {
  63. field[prefix + key] = 'text';
  64. delete options.text;
  65. } else {
  66. const isDescendingIndex = Number(index) === -1;
  67. field[prefix + key] = isDescendingIndex ? -1 : 1;
  68. }
  69. delete options.type;
  70. if (!('background' in options)) {
  71. options.background = true;
  72. }
  73. if (schema.options.autoIndex != null) {
  74. options._autoIndex = schema.options.autoIndex;
  75. }
  76. const indexName = options && options.name;
  77. if (typeof indexName === 'string') {
  78. if (indexByName.has(indexName)) {
  79. Object.assign(indexByName.get(indexName), field);
  80. } else {
  81. indexes.push([field, options]);
  82. indexByName.set(indexName, field);
  83. }
  84. } else {
  85. indexes.push([field, options]);
  86. indexByName.set(indexName, field);
  87. }
  88. }
  89. }
  90. schemaStack.delete(schema);
  91. if (prefix) {
  92. fixSubIndexPaths(schema, prefix);
  93. } else {
  94. schema._indexes.forEach(function(index) {
  95. const options = index[1];
  96. if (!('background' in options)) {
  97. options.background = true;
  98. }
  99. decorateDiscriminatorIndexOptions(schema, options);
  100. });
  101. indexes = indexes.concat(schema._indexes);
  102. }
  103. }
  104. /*!
  105. * Checks for indexes added to subdocs using Schema.index().
  106. * These indexes need their paths prefixed properly.
  107. *
  108. * schema._indexes = [ [indexObj, options], [indexObj, options] ..]
  109. */
  110. function fixSubIndexPaths(schema, prefix) {
  111. const subindexes = schema._indexes;
  112. const len = subindexes.length;
  113. for (let i = 0; i < len; ++i) {
  114. const indexObj = subindexes[i][0];
  115. const indexOptions = subindexes[i][1];
  116. const keys = Object.keys(indexObj);
  117. const klen = keys.length;
  118. const newindex = {};
  119. // use forward iteration, order matters
  120. for (let j = 0; j < klen; ++j) {
  121. const key = keys[j];
  122. newindex[prefix + key] = indexObj[key];
  123. }
  124. const newIndexOptions = Object.assign({}, indexOptions);
  125. if (indexOptions != null && indexOptions.partialFilterExpression != null) {
  126. newIndexOptions.partialFilterExpression = {};
  127. const partialFilterExpression = indexOptions.partialFilterExpression;
  128. for (const key of Object.keys(partialFilterExpression)) {
  129. newIndexOptions.partialFilterExpression[prefix + key] =
  130. partialFilterExpression[key];
  131. }
  132. }
  133. indexes.push([newindex, newIndexOptions]);
  134. }
  135. }
  136. };