Skip to content

Commit

Permalink
Merge pull request #15175 from Automattic/vkarpov15/sync-indexes-tocr…
Browse files Browse the repository at this point in the history
…eate

feat(model): make `syncIndexes()` not call `createIndex()` on indexes that already exist
  • Loading branch information
vkarpov15 authored Jan 11, 2025
2 parents dcca5ca + ee8bf75 commit 67a30e7
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 13 deletions.
26 changes: 13 additions & 13 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ Model.syncIndexes = async function syncIndexes(options) {
}
}

const diffIndexesResult = await this.diffIndexes();
const diffIndexesResult = await this.diffIndexes({ indexOptionsToCreate: true });
const dropped = await this.cleanIndexes({ ...options, toDrop: diffIndexesResult.toDrop });
await this.createIndexes({ ...options, toCreate: diffIndexesResult.toCreate });

Expand Down Expand Up @@ -1419,13 +1419,14 @@ Model.listSearchIndexes = async function listSearchIndexes(options) {
*
* const { toDrop, toCreate } = await Model.diffIndexes();
* toDrop; // Array of strings containing names of indexes that `syncIndexes()` will drop
* toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create
* toCreate; // Array of index specs containing the keys of indexes that `syncIndexes()` will create
*
* @param {Object} [options]
* @param {Boolean} [options.indexOptionsToCreate=false] If true, `toCreate` will include both the index spec and the index options, not just the index spec
* @return {Promise<Object>} contains the indexes that would be dropped in MongoDB and indexes that would be created in MongoDB as `{ toDrop: string[], toCreate: string[] }`.
*/

Model.diffIndexes = async function diffIndexes() {
Model.diffIndexes = async function diffIndexes(options) {
if (typeof arguments[0] === 'function' || typeof arguments[1] === 'function') {
throw new MongooseError('Model.syncIndexes() no longer accepts a callback');
}
Expand All @@ -1447,13 +1448,14 @@ Model.diffIndexes = async function diffIndexes() {
const schemaIndexes = getRelatedSchemaIndexes(model, schema.indexes());

const toDrop = getIndexesToDrop(schema, schemaIndexes, dbIndexes);
const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop);
const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop, options);

return { toDrop, toCreate };
};

function getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop) {
function getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop, options) {
const toCreate = [];
const indexOptionsToCreate = options?.indexOptionsToCreate ?? false;

for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) {
let found = false;
Expand All @@ -1474,7 +1476,11 @@ function getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop) {
}

if (!found) {
toCreate.push(schemaIndexKeysObject);
if (indexOptionsToCreate) {
toCreate.push([schemaIndexKeysObject, schemaIndexOptions]);
} else {
toCreate.push(schemaIndexKeysObject);
}
}
}

Expand Down Expand Up @@ -1655,7 +1661,7 @@ Model.createIndexes = async function createIndexes(options) {
*/

function _ensureIndexes(model, options, callback) {
const indexes = model.schema.indexes();
const indexes = Array.isArray(options?.toCreate) ? options.toCreate : model.schema.indexes();
let indexError;

options = options || {};
Expand Down Expand Up @@ -1739,12 +1745,6 @@ function _ensureIndexes(model, options, callback) {
indexOptions.background = options.background;
}

if ('toCreate' in options) {
if (options.toCreate.length === 0) {
return done();
}
}

// Just in case `createIndex()` throws a sync error
let promise = null;
try {
Expand Down
20 changes: 20 additions & 0 deletions test/model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5078,6 +5078,26 @@ describe('Model', function() {
assert.strictEqual(indexes[1].background, false);
});

it('syncIndexes() does not call createIndex for indexes that already exist', async function() {
const opts = { autoIndex: false };
const schema = new Schema({ name: String }, opts);
schema.index({ name: 1 }, { background: true });

const M = db.model('Test', schema);
await M.syncIndexes();

const indexes = await M.listIndexes();
assert.deepEqual(indexes[1].key, { name: 1 });

sinon.stub(M.collection, 'createIndex').callsFake(() => Promise.resolve());
try {
await M.syncIndexes();
assert.equal(M.collection.createIndex.getCalls().length, 0);
} finally {
sinon.restore();
}
});

it('syncIndexes() supports hideIndexes (gh-14868)', async function() {
const opts = { autoIndex: false };
const schema = new Schema({ name: String }, opts);
Expand Down

0 comments on commit 67a30e7

Please sign in to comment.