Skip to content

Commit 67a30e7

Browse files
authored
Merge pull request Automattic#15175 from Automattic/vkarpov15/sync-indexes-tocreate
feat(model): make `syncIndexes()` not call `createIndex()` on indexes that already exist
2 parents dcca5ca + ee8bf75 commit 67a30e7

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

lib/model.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,7 @@ Model.syncIndexes = async function syncIndexes(options) {
13141314
}
13151315
}
13161316

1317-
const diffIndexesResult = await this.diffIndexes();
1317+
const diffIndexesResult = await this.diffIndexes({ indexOptionsToCreate: true });
13181318
const dropped = await this.cleanIndexes({ ...options, toDrop: diffIndexesResult.toDrop });
13191319
await this.createIndexes({ ...options, toCreate: diffIndexesResult.toCreate });
13201320

@@ -1419,13 +1419,14 @@ Model.listSearchIndexes = async function listSearchIndexes(options) {
14191419
*
14201420
* const { toDrop, toCreate } = await Model.diffIndexes();
14211421
* toDrop; // Array of strings containing names of indexes that `syncIndexes()` will drop
1422-
* toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create
1422+
* toCreate; // Array of index specs containing the keys of indexes that `syncIndexes()` will create
14231423
*
14241424
* @param {Object} [options]
1425+
* @param {Boolean} [options.indexOptionsToCreate=false] If true, `toCreate` will include both the index spec and the index options, not just the index spec
14251426
* @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[] }`.
14261427
*/
14271428

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

14491450
const toDrop = getIndexesToDrop(schema, schemaIndexes, dbIndexes);
1450-
const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop);
1451+
const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop, options);
14511452

14521453
return { toDrop, toCreate };
14531454
};
14541455

1455-
function getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop) {
1456+
function getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop, options) {
14561457
const toCreate = [];
1458+
const indexOptionsToCreate = options?.indexOptionsToCreate ?? false;
14571459

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

14761478
if (!found) {
1477-
toCreate.push(schemaIndexKeysObject);
1479+
if (indexOptionsToCreate) {
1480+
toCreate.push([schemaIndexKeysObject, schemaIndexOptions]);
1481+
} else {
1482+
toCreate.push(schemaIndexKeysObject);
1483+
}
14781484
}
14791485
}
14801486

@@ -1655,7 +1661,7 @@ Model.createIndexes = async function createIndexes(options) {
16551661
*/
16561662

16571663
function _ensureIndexes(model, options, callback) {
1658-
const indexes = model.schema.indexes();
1664+
const indexes = Array.isArray(options?.toCreate) ? options.toCreate : model.schema.indexes();
16591665
let indexError;
16601666

16611667
options = options || {};
@@ -1739,12 +1745,6 @@ function _ensureIndexes(model, options, callback) {
17391745
indexOptions.background = options.background;
17401746
}
17411747

1742-
if ('toCreate' in options) {
1743-
if (options.toCreate.length === 0) {
1744-
return done();
1745-
}
1746-
}
1747-
17481748
// Just in case `createIndex()` throws a sync error
17491749
let promise = null;
17501750
try {

test/model.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5078,6 +5078,26 @@ describe('Model', function() {
50785078
assert.strictEqual(indexes[1].background, false);
50795079
});
50805080

5081+
it('syncIndexes() does not call createIndex for indexes that already exist', async function() {
5082+
const opts = { autoIndex: false };
5083+
const schema = new Schema({ name: String }, opts);
5084+
schema.index({ name: 1 }, { background: true });
5085+
5086+
const M = db.model('Test', schema);
5087+
await M.syncIndexes();
5088+
5089+
const indexes = await M.listIndexes();
5090+
assert.deepEqual(indexes[1].key, { name: 1 });
5091+
5092+
sinon.stub(M.collection, 'createIndex').callsFake(() => Promise.resolve());
5093+
try {
5094+
await M.syncIndexes();
5095+
assert.equal(M.collection.createIndex.getCalls().length, 0);
5096+
} finally {
5097+
sinon.restore();
5098+
}
5099+
});
5100+
50815101
it('syncIndexes() supports hideIndexes (gh-14868)', async function() {
50825102
const opts = { autoIndex: false };
50835103
const schema = new Schema({ name: String }, opts);

0 commit comments

Comments
 (0)