getIndexes.js 4.8 KB

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