Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-4634): add support for bulk FindOperators.hint() #3408

Merged
merged 4 commits into from Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/bulk/common.ts
Expand Up @@ -784,7 +784,7 @@ export class FindOperators {
}

/** Add a multiple update operation to the bulk operation */
update(updateDocument: Document): BulkOperationBase {
update(updateDocument: Document | Document[]): BulkOperationBase {
const currentOp = buildCurrentOp(this.bulkOperation);
return this.bulkOperation.addToOperationsList(
BatchType.UPDATE,
Expand All @@ -796,7 +796,7 @@ export class FindOperators {
}

/** Add a single update operation to the bulk operation */
updateOne(updateDocument: Document): BulkOperationBase {
updateOne(updateDocument: Document | Document[]): BulkOperationBase {
if (!hasAtomicOperators(updateDocument)) {
throw new MongoInvalidArgumentError('Update document requires atomic operators');
}
Expand Down Expand Up @@ -868,6 +868,16 @@ export class FindOperators {
this.bulkOperation.s.currentOp.arrayFilters = arrayFilters;
return this;
}

/** Specifies hint for the bulk operation. */
hint(hint: Hint): this {
if (!this.bulkOperation.s.currentOp) {
this.bulkOperation.s.currentOp = {};
}

this.bulkOperation.s.currentOp.hint = hint;
return this;
}
}

/** @internal */
Expand Down
4 changes: 2 additions & 2 deletions src/operations/update.ts
Expand Up @@ -22,7 +22,7 @@ export interface UpdateOptions extends CommandOperationOptions {
/** Specifies a collation */
collation?: CollationOptions;
/** Specify that the update query should only consider plans using the hinted index */
hint?: string | Document;
hint?: Hint;
/** When true, creates a new document if no document matches the query */
upsert?: boolean;
/** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */
Expand Down Expand Up @@ -280,7 +280,7 @@ export class ReplaceOneOperation extends UpdateOperation {

export function makeUpdateStatement(
filter: Document,
update: Document,
update: Document | Document[],
options: UpdateOptions & { multi?: boolean }
): UpdateStatement {
if (filter == null || typeof filter !== 'object') {
Expand Down
63 changes: 63 additions & 0 deletions test/integration/crud/bulk.test.ts
Expand Up @@ -1688,6 +1688,51 @@ describe('Bulk', function () {
}
});

it('should apply hint via FindOperators', {
metadata: { requires: { mongodb: '>= 4.4' } },
async test() {
const bulk = client.db().collection('coll').initializeOrderedBulkOp();

const events = [];
client.on('commandStarted', event => {
if (['update', 'delete'].includes(event.commandName)) {
events.push(event);
}
});

// updates
bulk
.find({ b: 1 })
.hint({ b: 1 })
.updateOne({ $set: { b: 2 } });
bulk
.find({ b: 2 })
.hint({ b: 1 })
.update({ $set: { b: 3 } });
bulk.find({ b: 3 }).hint({ b: 1 }).replaceOne({ b: 2 });

// deletes
bulk.find({ b: 2 }).hint({ b: 1 }).deleteOne();
bulk.find({ b: 1 }).hint({ b: 1 }).delete();

await bulk.execute();

expect(events).to.be.an('array').with.length.at.least(1);
expect(events[0]).property('commandName').to.equal('update');
const updateCommand = events[0].command;
expect(updateCommand).property('updates').to.be.an('array').with.length(3);
updateCommand.updates.forEach(statement => {
expect(statement).property('hint').to.eql({ b: 1 });
});
expect(events[1]).property('commandName').to.equal('delete');
const deleteCommand = events[1].command;
expect(deleteCommand).property('deletes').to.be.an('array').with.length(2);
deleteCommand.deletes.forEach(statement => {
expect(statement).property('hint').to.eql({ b: 1 });
});
}
});

it('should apply arrayFilters to bulk updates via FindOperators', {
metadata: { requires: { mongodb: '>= 3.6' } },
test: function (done) {
Expand Down Expand Up @@ -1737,6 +1782,24 @@ describe('Bulk', function () {
}
});

it('should accept pipeline-style updates', {
metadata: { requires: { mongodb: '>= 4.2' } },
async test() {
const coll = client.db().collection('coll');
const bulk = coll.initializeOrderedBulkOp();

coll.insertMany([{ a: 1 }, { a: 2 }]);

bulk.find({ a: 1 }).updateOne([{ $project: { a: { $add: ['$a', 10] } } }]);
bulk.find({ a: 2 }).update([{ $project: { a: { $add: ['$a', 100] } } }]);

await bulk.execute();

const contents = await coll.find().project({ _id: 0 }).toArray();
expect(contents).to.deep.equal([{ a: 11 }, { a: 102 }]);
}
});

it('should throw an error if raw operations are passed to bulkWrite', function () {
const coll = client.db().collection('single_bulk_write_error');
return coll
Expand Down