isIndexEqual.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. const get = require('../get');
  3. const utils = require('../../utils');
  4. /**
  5. * Given a Mongoose index definition (key + options objects) and a MongoDB server
  6. * index definition, determine if the two indexes are equal.
  7. *
  8. * @param {Object} key the Mongoose index spec
  9. * @param {Object} options the Mongoose index definition's options
  10. * @param {Object} dbIndex the index in MongoDB as returned by `listIndexes()`
  11. * @api private
  12. */
  13. module.exports = function isIndexEqual(key, options, dbIndex) {
  14. // Special case: text indexes have a special format in the db. For example,
  15. // `{ name: 'text' }` becomes:
  16. // {
  17. // v: 2,
  18. // key: { _fts: 'text', _ftsx: 1 },
  19. // name: 'name_text',
  20. // ns: 'test.tests',
  21. // background: true,
  22. // weights: { name: 1 },
  23. // default_language: 'english',
  24. // language_override: 'language',
  25. // textIndexVersion: 3
  26. // }
  27. if (dbIndex.textIndexVersion != null) {
  28. delete dbIndex.key._fts;
  29. delete dbIndex.key._ftsx;
  30. const weights = { ...dbIndex.weights, ...dbIndex.key };
  31. if (Object.keys(weights).length !== Object.keys(key).length) {
  32. return false;
  33. }
  34. for (const prop of Object.keys(weights)) {
  35. if (!(prop in key)) {
  36. return false;
  37. }
  38. const weight = weights[prop];
  39. if (weight !== get(options, 'weights.' + prop) && !(weight === 1 && get(options, 'weights.' + prop) == null)) {
  40. return false;
  41. }
  42. }
  43. if (options['default_language'] !== dbIndex['default_language']) {
  44. return dbIndex['default_language'] === 'english' && options['default_language'] == null;
  45. }
  46. return true;
  47. }
  48. const optionKeys = [
  49. 'unique',
  50. 'partialFilterExpression',
  51. 'sparse',
  52. 'expireAfterSeconds',
  53. 'collation'
  54. ];
  55. for (const key of optionKeys) {
  56. if (!(key in options) && !(key in dbIndex)) {
  57. continue;
  58. }
  59. if (key === 'collation') {
  60. if (options[key] == null || dbIndex[key] == null) {
  61. return options[key] == null && dbIndex[key] == null;
  62. }
  63. const definedKeys = Object.keys(options.collation);
  64. const schemaCollation = options.collation;
  65. const dbCollation = dbIndex.collation;
  66. for (const opt of definedKeys) {
  67. if (get(schemaCollation, opt) !== get(dbCollation, opt)) {
  68. return false;
  69. }
  70. }
  71. } else if (!utils.deepEqual(options[key], dbIndex[key])) {
  72. return false;
  73. }
  74. }
  75. const schemaIndexKeys = Object.keys(key);
  76. const dbIndexKeys = Object.keys(dbIndex.key);
  77. if (schemaIndexKeys.length !== dbIndexKeys.length) {
  78. return false;
  79. }
  80. for (let i = 0; i < schemaIndexKeys.length; ++i) {
  81. if (schemaIndexKeys[i] !== dbIndexKeys[i]) {
  82. return false;
  83. }
  84. if (!utils.deepEqual(key[schemaIndexKeys[i]], dbIndex.key[dbIndexKeys[i]])) {
  85. return false;
  86. }
  87. }
  88. return true;
  89. };