mongodb 6.9.0 → 6.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/beta.d.ts +407 -12
- package/lib/bson.js +1 -0
- package/lib/bson.js.map +1 -1
- package/lib/bulk/common.js +60 -71
- package/lib/bulk/common.js.map +1 -1
- package/lib/bulk/unordered.js +3 -3
- package/lib/bulk/unordered.js.map +1 -1
- package/lib/change_stream.js +3 -2
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +2 -7
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/command_builders.js +1 -1
- package/lib/cmap/auth/mongodb_oidc/command_builders.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/human_callback_workflow.js +1 -1
- package/lib/cmap/auth/mongodb_oidc/human_callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/machine_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +10 -1
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +50 -18
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connection.js +9 -2
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/wire_protocol/constants.js +2 -2
- package/lib/cmap/wire_protocol/on_demand/document.js.map +1 -1
- package/lib/cmap/wire_protocol/responses.js +26 -1
- package/lib/cmap/wire_protocol/responses.js.map +1 -1
- package/lib/connection_string.js +1 -7
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/client_bulk_write_cursor.js +52 -0
- package/lib/cursor/client_bulk_write_cursor.js.map +1 -0
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/db.js +1 -1
- package/lib/error.js +76 -3
- package/lib/error.js.map +1 -1
- package/lib/explain.js +6 -6
- package/lib/explain.js.map +1 -1
- package/lib/index.js +6 -3
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +14 -0
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_client_auth_providers.js +6 -2
- package/lib/mongo_client_auth_providers.js.map +1 -1
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/client_bulk_write/client_bulk_write.js +83 -0
- package/lib/operations/client_bulk_write/client_bulk_write.js.map +1 -0
- package/lib/operations/client_bulk_write/command_builder.js +154 -19
- package/lib/operations/client_bulk_write/command_builder.js.map +1 -1
- package/lib/operations/client_bulk_write/executor.js +109 -0
- package/lib/operations/client_bulk_write/executor.js.map +1 -0
- package/lib/operations/client_bulk_write/results_merger.js +204 -0
- package/lib/operations/client_bulk_write/results_merger.js.map +1 -0
- package/lib/operations/execute_operation.js +7 -0
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/operation.js +5 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/operations/search_indexes/create.js.map +1 -1
- package/lib/operations/search_indexes/drop.js.map +1 -1
- package/lib/operations/search_indexes/update.js.map +1 -1
- package/lib/sdam/server.js +2 -1
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +3 -0
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/srv_polling.js +5 -1
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +9 -2
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +25 -9
- package/lib/utils.js.map +1 -1
- package/lib/write_concern.js.map +1 -1
- package/mongodb.d.ts +407 -12
- package/package.json +1 -1
- package/src/beta.ts +1 -1
- package/src/bson.ts +3 -0
- package/src/bulk/common.ts +80 -120
- package/src/bulk/unordered.ts +3 -4
- package/src/change_stream.ts +5 -2
- package/src/cmap/auth/mongo_credentials.ts +2 -8
- package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +1 -1
- package/src/cmap/auth/mongodb_oidc/command_builders.ts +1 -2
- package/src/cmap/auth/mongodb_oidc/human_callback_workflow.ts +1 -2
- package/src/cmap/auth/mongodb_oidc/machine_workflow.ts +1 -1
- package/src/cmap/auth/mongodb_oidc.ts +1 -2
- package/src/cmap/command_monitoring_events.ts +16 -2
- package/src/cmap/commands.ts +71 -25
- package/src/cmap/connection.ts +17 -4
- package/src/cmap/wire_protocol/constants.ts +2 -2
- package/src/cmap/wire_protocol/on_demand/document.ts +1 -2
- package/src/cmap/wire_protocol/responses.ts +31 -2
- package/src/connection_string.ts +2 -9
- package/src/cursor/aggregation_cursor.ts +2 -2
- package/src/cursor/client_bulk_write_cursor.ts +79 -0
- package/src/cursor/find_cursor.ts +2 -2
- package/src/db.ts +1 -1
- package/src/error.ts +98 -2
- package/src/explain.ts +47 -11
- package/src/index.ts +26 -1
- package/src/mongo_client.ts +29 -1
- package/src/mongo_client_auth_providers.ts +8 -2
- package/src/mongo_types.ts +2 -1
- package/src/operations/aggregate.ts +9 -1
- package/src/operations/client_bulk_write/client_bulk_write.ts +107 -0
- package/src/operations/client_bulk_write/command_builder.ts +216 -30
- package/src/operations/client_bulk_write/common.ts +148 -23
- package/src/operations/client_bulk_write/executor.ts +137 -0
- package/src/operations/client_bulk_write/results_merger.ts +260 -0
- package/src/operations/execute_operation.ts +8 -0
- package/src/operations/find.ts +8 -1
- package/src/operations/operation.ts +6 -1
- package/src/operations/search_indexes/create.ts +1 -2
- package/src/operations/search_indexes/drop.ts +1 -2
- package/src/operations/search_indexes/update.ts +1 -2
- package/src/sdam/server.ts +2 -1
- package/src/sdam/server_description.ts +9 -0
- package/src/sdam/srv_polling.ts +5 -2
- package/src/sdam/topology_description.ts +0 -1
- package/src/sessions.ts +16 -2
- package/src/utils.ts +40 -10
- package/src/write_concern.ts +4 -1
- package/lib/cmap/auth/mongocr.js +0 -35
- package/lib/cmap/auth/mongocr.js.map +0 -1
- package/src/cmap/auth/mongocr.ts +0 -38
|
@@ -27,25 +27,32 @@ export interface ClientBulkWriteOptions extends CommandOperationOptions {
|
|
|
27
27
|
|
|
28
28
|
/** @public */
|
|
29
29
|
export interface ClientWriteModel {
|
|
30
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* The namespace for the write.
|
|
32
|
+
*
|
|
33
|
+
* A namespace is a combination of the database name and the name of the collection: `<database-name>.<collection>`.
|
|
34
|
+
* All documents belong to a namespace.
|
|
35
|
+
*
|
|
36
|
+
* @see https://www.mongodb.com/docs/manual/reference/limits/#std-label-faq-dev-namespace
|
|
37
|
+
*/
|
|
31
38
|
namespace: string;
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
/** @public */
|
|
35
|
-
export interface ClientInsertOneModel extends ClientWriteModel {
|
|
42
|
+
export interface ClientInsertOneModel<TSchema> extends ClientWriteModel {
|
|
36
43
|
name: 'insertOne';
|
|
37
44
|
/** The document to insert. */
|
|
38
|
-
document: OptionalId<
|
|
45
|
+
document: OptionalId<TSchema>;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
/** @public */
|
|
42
|
-
export interface ClientDeleteOneModel extends ClientWriteModel {
|
|
49
|
+
export interface ClientDeleteOneModel<TSchema> extends ClientWriteModel {
|
|
43
50
|
name: 'deleteOne';
|
|
44
51
|
/**
|
|
45
52
|
* The filter used to determine if a document should be deleted.
|
|
46
53
|
* For a deleteOne operation, the first match is removed.
|
|
47
54
|
*/
|
|
48
|
-
filter: Filter<
|
|
55
|
+
filter: Filter<TSchema>;
|
|
49
56
|
/** Specifies a collation. */
|
|
50
57
|
collation?: CollationOptions;
|
|
51
58
|
/** The index to use. If specified, then the query system will only consider plans using the hinted index. */
|
|
@@ -53,13 +60,13 @@ export interface ClientDeleteOneModel extends ClientWriteModel {
|
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
/** @public */
|
|
56
|
-
export interface ClientDeleteManyModel extends ClientWriteModel {
|
|
63
|
+
export interface ClientDeleteManyModel<TSchema> extends ClientWriteModel {
|
|
57
64
|
name: 'deleteMany';
|
|
58
65
|
/**
|
|
59
66
|
* The filter used to determine if a document should be deleted.
|
|
60
67
|
* For a deleteMany operation, all matches are removed.
|
|
61
68
|
*/
|
|
62
|
-
filter: Filter<
|
|
69
|
+
filter: Filter<TSchema>;
|
|
63
70
|
/** Specifies a collation. */
|
|
64
71
|
collation?: CollationOptions;
|
|
65
72
|
/** The index to use. If specified, then the query system will only consider plans using the hinted index. */
|
|
@@ -67,15 +74,15 @@ export interface ClientDeleteManyModel extends ClientWriteModel {
|
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
/** @public */
|
|
70
|
-
export interface ClientReplaceOneModel extends ClientWriteModel {
|
|
77
|
+
export interface ClientReplaceOneModel<TSchema> extends ClientWriteModel {
|
|
71
78
|
name: 'replaceOne';
|
|
72
79
|
/**
|
|
73
80
|
* The filter used to determine if a document should be replaced.
|
|
74
81
|
* For a replaceOne operation, the first match is replaced.
|
|
75
82
|
*/
|
|
76
|
-
filter: Filter<
|
|
83
|
+
filter: Filter<TSchema>;
|
|
77
84
|
/** The document with which to replace the matched document. */
|
|
78
|
-
replacement: WithoutId<
|
|
85
|
+
replacement: WithoutId<TSchema>;
|
|
79
86
|
/** Specifies a collation. */
|
|
80
87
|
collation?: CollationOptions;
|
|
81
88
|
/** The index to use. If specified, then the query system will only consider plans using the hinted index. */
|
|
@@ -85,19 +92,19 @@ export interface ClientReplaceOneModel extends ClientWriteModel {
|
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
/** @public */
|
|
88
|
-
export interface ClientUpdateOneModel extends ClientWriteModel {
|
|
95
|
+
export interface ClientUpdateOneModel<TSchema> extends ClientWriteModel {
|
|
89
96
|
name: 'updateOne';
|
|
90
97
|
/**
|
|
91
98
|
* The filter used to determine if a document should be updated.
|
|
92
99
|
* For an updateOne operation, the first match is updated.
|
|
93
100
|
*/
|
|
94
|
-
filter: Filter<
|
|
101
|
+
filter: Filter<TSchema>;
|
|
95
102
|
/**
|
|
96
103
|
* The modifications to apply. The value can be either:
|
|
97
104
|
* UpdateFilter<Document> - A document that contains update operator expressions,
|
|
98
105
|
* Document[] - an aggregation pipeline.
|
|
99
106
|
*/
|
|
100
|
-
update: UpdateFilter<
|
|
107
|
+
update: UpdateFilter<TSchema> | Document[];
|
|
101
108
|
/** A set of filters specifying to which array elements an update should apply. */
|
|
102
109
|
arrayFilters?: Document[];
|
|
103
110
|
/** Specifies a collation. */
|
|
@@ -109,19 +116,19 @@ export interface ClientUpdateOneModel extends ClientWriteModel {
|
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
/** @public */
|
|
112
|
-
export interface ClientUpdateManyModel extends ClientWriteModel {
|
|
119
|
+
export interface ClientUpdateManyModel<TSchema> extends ClientWriteModel {
|
|
113
120
|
name: 'updateMany';
|
|
114
121
|
/**
|
|
115
122
|
* The filter used to determine if a document should be updated.
|
|
116
123
|
* For an updateMany operation, all matches are updated.
|
|
117
124
|
*/
|
|
118
|
-
filter: Filter<
|
|
125
|
+
filter: Filter<TSchema>;
|
|
119
126
|
/**
|
|
120
127
|
* The modifications to apply. The value can be either:
|
|
121
128
|
* UpdateFilter<Document> - A document that contains update operator expressions,
|
|
122
129
|
* Document[] - an aggregation pipeline.
|
|
123
130
|
*/
|
|
124
|
-
update: UpdateFilter<
|
|
131
|
+
update: UpdateFilter<TSchema> | Document[];
|
|
125
132
|
/** A set of filters specifying to which array elements an update should apply. */
|
|
126
133
|
arrayFilters?: Document[];
|
|
127
134
|
/** Specifies a collation. */
|
|
@@ -137,10 +144,128 @@ export interface ClientUpdateManyModel extends ClientWriteModel {
|
|
|
137
144
|
* to MongoClient#bulkWrite.
|
|
138
145
|
* @public
|
|
139
146
|
*/
|
|
140
|
-
export type AnyClientBulkWriteModel =
|
|
141
|
-
| ClientInsertOneModel
|
|
142
|
-
| ClientReplaceOneModel
|
|
143
|
-
| ClientUpdateOneModel
|
|
144
|
-
| ClientUpdateManyModel
|
|
145
|
-
| ClientDeleteOneModel
|
|
146
|
-
| ClientDeleteManyModel
|
|
147
|
+
export type AnyClientBulkWriteModel<TSchema extends Document> =
|
|
148
|
+
| ClientInsertOneModel<TSchema>
|
|
149
|
+
| ClientReplaceOneModel<TSchema>
|
|
150
|
+
| ClientUpdateOneModel<TSchema>
|
|
151
|
+
| ClientUpdateManyModel<TSchema>
|
|
152
|
+
| ClientDeleteOneModel<TSchema>
|
|
153
|
+
| ClientDeleteManyModel<TSchema>;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* A mapping of namespace strings to collections schemas.
|
|
157
|
+
* @public
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* type MongoDBSchemas = {
|
|
162
|
+
* 'db.books': Book;
|
|
163
|
+
* 'db.authors': Author;
|
|
164
|
+
* }
|
|
165
|
+
*
|
|
166
|
+
* const model: ClientBulkWriteModel<MongoDBSchemas> = {
|
|
167
|
+
* namespace: 'db.books'
|
|
168
|
+
* name: 'insertOne',
|
|
169
|
+
* document: { title: 'Practical MongoDB Aggregations', authorName: 3 } // error `authorName` cannot be number
|
|
170
|
+
* };
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* The type of the `namespace` field narrows other parts of the BulkWriteModel to use the correct schema for type assertions.
|
|
174
|
+
*
|
|
175
|
+
*/
|
|
176
|
+
export type ClientBulkWriteModel<
|
|
177
|
+
SchemaMap extends Record<string, Document> = Record<string, Document>
|
|
178
|
+
> = {
|
|
179
|
+
[Namespace in keyof SchemaMap]: AnyClientBulkWriteModel<SchemaMap[Namespace]> & {
|
|
180
|
+
namespace: Namespace;
|
|
181
|
+
};
|
|
182
|
+
}[keyof SchemaMap];
|
|
183
|
+
|
|
184
|
+
/** @public */
|
|
185
|
+
export interface ClientBulkWriteResult {
|
|
186
|
+
/**
|
|
187
|
+
* Whether the bulk write was acknowledged.
|
|
188
|
+
*/
|
|
189
|
+
readonly acknowledged: boolean;
|
|
190
|
+
/**
|
|
191
|
+
* The total number of documents inserted across all insert operations.
|
|
192
|
+
*/
|
|
193
|
+
readonly insertedCount: number;
|
|
194
|
+
/**
|
|
195
|
+
* The total number of documents upserted across all update operations.
|
|
196
|
+
*/
|
|
197
|
+
readonly upsertedCount: number;
|
|
198
|
+
/**
|
|
199
|
+
* The total number of documents matched across all update operations.
|
|
200
|
+
*/
|
|
201
|
+
readonly matchedCount: number;
|
|
202
|
+
/**
|
|
203
|
+
* The total number of documents modified across all update operations.
|
|
204
|
+
*/
|
|
205
|
+
readonly modifiedCount: number;
|
|
206
|
+
/**
|
|
207
|
+
* The total number of documents deleted across all delete operations.
|
|
208
|
+
*/
|
|
209
|
+
readonly deletedCount: number;
|
|
210
|
+
/**
|
|
211
|
+
* The results of each individual insert operation that was successfully performed.
|
|
212
|
+
*/
|
|
213
|
+
readonly insertResults?: ReadonlyMap<number, ClientInsertOneResult>;
|
|
214
|
+
/**
|
|
215
|
+
* The results of each individual update operation that was successfully performed.
|
|
216
|
+
*/
|
|
217
|
+
readonly updateResults?: ReadonlyMap<number, ClientUpdateResult>;
|
|
218
|
+
/**
|
|
219
|
+
* The results of each individual delete operation that was successfully performed.
|
|
220
|
+
*/
|
|
221
|
+
readonly deleteResults?: ReadonlyMap<number, ClientDeleteResult>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** @public */
|
|
225
|
+
export interface ClientBulkWriteError {
|
|
226
|
+
code: number;
|
|
227
|
+
message: string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** @public */
|
|
231
|
+
export interface ClientInsertOneResult {
|
|
232
|
+
/**
|
|
233
|
+
* The _id of the inserted document.
|
|
234
|
+
*/
|
|
235
|
+
insertedId: any;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** @public */
|
|
239
|
+
export interface ClientUpdateResult {
|
|
240
|
+
/**
|
|
241
|
+
* The number of documents that matched the filter.
|
|
242
|
+
*/
|
|
243
|
+
matchedCount: number;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The number of documents that were modified.
|
|
247
|
+
*/
|
|
248
|
+
modifiedCount: number;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The _id field of the upserted document if an upsert occurred.
|
|
252
|
+
*
|
|
253
|
+
* It MUST be possible to discern between a BSON Null upserted ID value and this field being
|
|
254
|
+
* unset. If necessary, drivers MAY add a didUpsert boolean field to differentiate between
|
|
255
|
+
* these two cases.
|
|
256
|
+
*/
|
|
257
|
+
upsertedId?: any;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Determines if the upsert did include an _id, which includes the case of the _id being null.
|
|
261
|
+
*/
|
|
262
|
+
didUpsert: boolean;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** @public */
|
|
266
|
+
export interface ClientDeleteResult {
|
|
267
|
+
/**
|
|
268
|
+
* The number of documents that were deleted.
|
|
269
|
+
*/
|
|
270
|
+
deletedCount: number;
|
|
271
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { type Document } from '../../bson';
|
|
2
|
+
import { ClientBulkWriteCursor } from '../../cursor/client_bulk_write_cursor';
|
|
3
|
+
import {
|
|
4
|
+
MongoClientBulkWriteError,
|
|
5
|
+
MongoClientBulkWriteExecutionError,
|
|
6
|
+
MongoInvalidArgumentError,
|
|
7
|
+
MongoServerError
|
|
8
|
+
} from '../../error';
|
|
9
|
+
import { type MongoClient } from '../../mongo_client';
|
|
10
|
+
import { WriteConcern } from '../../write_concern';
|
|
11
|
+
import { executeOperation } from '../execute_operation';
|
|
12
|
+
import { ClientBulkWriteOperation } from './client_bulk_write';
|
|
13
|
+
import { ClientBulkWriteCommandBuilder } from './command_builder';
|
|
14
|
+
import {
|
|
15
|
+
type AnyClientBulkWriteModel,
|
|
16
|
+
type ClientBulkWriteOptions,
|
|
17
|
+
type ClientBulkWriteResult
|
|
18
|
+
} from './common';
|
|
19
|
+
import { ClientBulkWriteResultsMerger } from './results_merger';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Responsible for executing a client bulk write.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export class ClientBulkWriteExecutor {
|
|
26
|
+
private readonly client: MongoClient;
|
|
27
|
+
private readonly options: ClientBulkWriteOptions;
|
|
28
|
+
private readonly operations: ReadonlyArray<AnyClientBulkWriteModel<Document>>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Instantiate the executor.
|
|
32
|
+
* @param client - The mongo client.
|
|
33
|
+
* @param operations - The user supplied bulk write models.
|
|
34
|
+
* @param options - The bulk write options.
|
|
35
|
+
*/
|
|
36
|
+
constructor(
|
|
37
|
+
client: MongoClient,
|
|
38
|
+
operations: ReadonlyArray<AnyClientBulkWriteModel<Document>>,
|
|
39
|
+
options?: ClientBulkWriteOptions
|
|
40
|
+
) {
|
|
41
|
+
if (operations.length === 0) {
|
|
42
|
+
throw new MongoClientBulkWriteExecutionError('No client bulk write models were provided.');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.client = client;
|
|
46
|
+
this.operations = operations;
|
|
47
|
+
this.options = {
|
|
48
|
+
ordered: true,
|
|
49
|
+
bypassDocumentValidation: false,
|
|
50
|
+
verboseResults: false,
|
|
51
|
+
...options
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// If no write concern was provided, we inherit one from the client.
|
|
55
|
+
if (!this.options.writeConcern) {
|
|
56
|
+
this.options.writeConcern = WriteConcern.fromOptions(this.client.options);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (this.options.writeConcern?.w === 0) {
|
|
60
|
+
if (this.options.verboseResults) {
|
|
61
|
+
throw new MongoInvalidArgumentError(
|
|
62
|
+
'Cannot request unacknowledged write concern and verbose results'
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (this.options.ordered) {
|
|
67
|
+
throw new MongoInvalidArgumentError(
|
|
68
|
+
'Cannot request unacknowledged write concern and ordered writes'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Execute the client bulk write. Will split commands into batches and exhaust the cursors
|
|
76
|
+
* for each, then merge the results into one.
|
|
77
|
+
* @returns The result.
|
|
78
|
+
*/
|
|
79
|
+
async execute(): Promise<ClientBulkWriteResult> {
|
|
80
|
+
// The command builder will take the user provided models and potential split the batch
|
|
81
|
+
// into multiple commands due to size.
|
|
82
|
+
const pkFactory = this.client.s.options.pkFactory;
|
|
83
|
+
const commandBuilder = new ClientBulkWriteCommandBuilder(
|
|
84
|
+
this.operations,
|
|
85
|
+
this.options,
|
|
86
|
+
pkFactory
|
|
87
|
+
);
|
|
88
|
+
// Unacknowledged writes need to execute all batches and return { ok: 1}
|
|
89
|
+
if (this.options.writeConcern?.w === 0) {
|
|
90
|
+
while (commandBuilder.hasNextBatch()) {
|
|
91
|
+
const operation = new ClientBulkWriteOperation(commandBuilder, this.options);
|
|
92
|
+
await executeOperation(this.client, operation);
|
|
93
|
+
}
|
|
94
|
+
return ClientBulkWriteResultsMerger.unacknowledged();
|
|
95
|
+
} else {
|
|
96
|
+
const resultsMerger = new ClientBulkWriteResultsMerger(this.options);
|
|
97
|
+
// For each command will will create and exhaust a cursor for the results.
|
|
98
|
+
while (commandBuilder.hasNextBatch()) {
|
|
99
|
+
const cursor = new ClientBulkWriteCursor(this.client, commandBuilder, this.options);
|
|
100
|
+
try {
|
|
101
|
+
await resultsMerger.merge(cursor);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
// Write concern errors are recorded in the writeConcernErrors field on MongoClientBulkWriteError.
|
|
104
|
+
// When a write concern error is encountered, it should not terminate execution of the bulk write
|
|
105
|
+
// for either ordered or unordered bulk writes. However, drivers MUST throw an exception at the end
|
|
106
|
+
// of execution if any write concern errors were observed.
|
|
107
|
+
if (error instanceof MongoServerError && !(error instanceof MongoClientBulkWriteError)) {
|
|
108
|
+
// Server side errors need to be wrapped inside a MongoClientBulkWriteError, where the root
|
|
109
|
+
// cause is the error property and a partial result is to be included.
|
|
110
|
+
const bulkWriteError = new MongoClientBulkWriteError({
|
|
111
|
+
message: 'Mongo client bulk write encountered an error during execution'
|
|
112
|
+
});
|
|
113
|
+
bulkWriteError.cause = error;
|
|
114
|
+
bulkWriteError.partialResult = resultsMerger.bulkWriteResult;
|
|
115
|
+
throw bulkWriteError;
|
|
116
|
+
} else {
|
|
117
|
+
// Client side errors are just thrown.
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// If we have write concern errors or unordered write errors at the end we throw.
|
|
124
|
+
if (resultsMerger.writeConcernErrors.length > 0 || resultsMerger.writeErrors.size > 0) {
|
|
125
|
+
const error = new MongoClientBulkWriteError({
|
|
126
|
+
message: 'Mongo client bulk write encountered errors during execution.'
|
|
127
|
+
});
|
|
128
|
+
error.writeConcernErrors = resultsMerger.writeConcernErrors;
|
|
129
|
+
error.writeErrors = resultsMerger.writeErrors;
|
|
130
|
+
error.partialResult = resultsMerger.bulkWriteResult;
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return resultsMerger.bulkWriteResult;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { MongoWriteConcernError } from '../..';
|
|
2
|
+
import { type Document } from '../../bson';
|
|
3
|
+
import { type ClientBulkWriteCursor } from '../../cursor/client_bulk_write_cursor';
|
|
4
|
+
import { MongoClientBulkWriteError } from '../../error';
|
|
5
|
+
import {
|
|
6
|
+
type ClientBulkWriteError,
|
|
7
|
+
type ClientBulkWriteOptions,
|
|
8
|
+
type ClientBulkWriteResult,
|
|
9
|
+
type ClientDeleteResult,
|
|
10
|
+
type ClientInsertOneResult,
|
|
11
|
+
type ClientUpdateResult
|
|
12
|
+
} from './common';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Unacknowledged bulk writes are always the same.
|
|
16
|
+
*/
|
|
17
|
+
const UNACKNOWLEDGED = {
|
|
18
|
+
acknowledged: false,
|
|
19
|
+
insertedCount: 0,
|
|
20
|
+
upsertedCount: 0,
|
|
21
|
+
matchedCount: 0,
|
|
22
|
+
modifiedCount: 0,
|
|
23
|
+
deletedCount: 0,
|
|
24
|
+
insertResults: undefined,
|
|
25
|
+
updateResults: undefined,
|
|
26
|
+
deleteResults: undefined
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
interface ClientBulkWriteResultAccumulation {
|
|
30
|
+
/**
|
|
31
|
+
* Whether the bulk write was acknowledged.
|
|
32
|
+
*/
|
|
33
|
+
acknowledged: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* The total number of documents inserted across all insert operations.
|
|
36
|
+
*/
|
|
37
|
+
insertedCount: number;
|
|
38
|
+
/**
|
|
39
|
+
* The total number of documents upserted across all update operations.
|
|
40
|
+
*/
|
|
41
|
+
upsertedCount: number;
|
|
42
|
+
/**
|
|
43
|
+
* The total number of documents matched across all update operations.
|
|
44
|
+
*/
|
|
45
|
+
matchedCount: number;
|
|
46
|
+
/**
|
|
47
|
+
* The total number of documents modified across all update operations.
|
|
48
|
+
*/
|
|
49
|
+
modifiedCount: number;
|
|
50
|
+
/**
|
|
51
|
+
* The total number of documents deleted across all delete operations.
|
|
52
|
+
*/
|
|
53
|
+
deletedCount: number;
|
|
54
|
+
/**
|
|
55
|
+
* The results of each individual insert operation that was successfully performed.
|
|
56
|
+
*/
|
|
57
|
+
insertResults?: Map<number, ClientInsertOneResult>;
|
|
58
|
+
/**
|
|
59
|
+
* The results of each individual update operation that was successfully performed.
|
|
60
|
+
*/
|
|
61
|
+
updateResults?: Map<number, ClientUpdateResult>;
|
|
62
|
+
/**
|
|
63
|
+
* The results of each individual delete operation that was successfully performed.
|
|
64
|
+
*/
|
|
65
|
+
deleteResults?: Map<number, ClientDeleteResult>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Merges client bulk write cursor responses together into a single result.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
export class ClientBulkWriteResultsMerger {
|
|
73
|
+
private result: ClientBulkWriteResultAccumulation;
|
|
74
|
+
private options: ClientBulkWriteOptions;
|
|
75
|
+
private currentBatchOffset: number;
|
|
76
|
+
writeConcernErrors: Document[];
|
|
77
|
+
writeErrors: Map<number, ClientBulkWriteError>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @returns The standard unacknowledged bulk write result.
|
|
81
|
+
*/
|
|
82
|
+
static unacknowledged(): ClientBulkWriteResult {
|
|
83
|
+
return UNACKNOWLEDGED;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Instantiate the merger.
|
|
88
|
+
* @param options - The options.
|
|
89
|
+
*/
|
|
90
|
+
constructor(options: ClientBulkWriteOptions) {
|
|
91
|
+
this.options = options;
|
|
92
|
+
this.currentBatchOffset = 0;
|
|
93
|
+
this.writeConcernErrors = [];
|
|
94
|
+
this.writeErrors = new Map();
|
|
95
|
+
this.result = {
|
|
96
|
+
acknowledged: true,
|
|
97
|
+
insertedCount: 0,
|
|
98
|
+
upsertedCount: 0,
|
|
99
|
+
matchedCount: 0,
|
|
100
|
+
modifiedCount: 0,
|
|
101
|
+
deletedCount: 0,
|
|
102
|
+
insertResults: undefined,
|
|
103
|
+
updateResults: undefined,
|
|
104
|
+
deleteResults: undefined
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
if (options.verboseResults) {
|
|
108
|
+
this.result.insertResults = new Map<number, ClientInsertOneResult>();
|
|
109
|
+
this.result.updateResults = new Map<number, ClientUpdateResult>();
|
|
110
|
+
this.result.deleteResults = new Map<number, ClientDeleteResult>();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get the bulk write result object.
|
|
116
|
+
*/
|
|
117
|
+
get bulkWriteResult(): ClientBulkWriteResult {
|
|
118
|
+
return {
|
|
119
|
+
acknowledged: this.result.acknowledged,
|
|
120
|
+
insertedCount: this.result.insertedCount,
|
|
121
|
+
upsertedCount: this.result.upsertedCount,
|
|
122
|
+
matchedCount: this.result.matchedCount,
|
|
123
|
+
modifiedCount: this.result.modifiedCount,
|
|
124
|
+
deletedCount: this.result.deletedCount,
|
|
125
|
+
insertResults: this.result.insertResults,
|
|
126
|
+
updateResults: this.result.updateResults,
|
|
127
|
+
deleteResults: this.result.deleteResults
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Merge the results in the cursor to the existing result.
|
|
133
|
+
* @param currentBatchOffset - The offset index to the original models.
|
|
134
|
+
* @param response - The cursor response.
|
|
135
|
+
* @param documents - The documents in the cursor.
|
|
136
|
+
* @returns The current result.
|
|
137
|
+
*/
|
|
138
|
+
async merge(cursor: ClientBulkWriteCursor): Promise<ClientBulkWriteResult> {
|
|
139
|
+
let writeConcernErrorResult;
|
|
140
|
+
try {
|
|
141
|
+
for await (const document of cursor) {
|
|
142
|
+
// Only add to maps if ok: 1
|
|
143
|
+
if (document.ok === 1) {
|
|
144
|
+
if (this.options.verboseResults) {
|
|
145
|
+
this.processDocument(cursor, document);
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
// If an individual write error is encountered during an ordered bulk write, drivers MUST
|
|
149
|
+
// record the error in writeErrors and immediately throw the exception. Otherwise, drivers
|
|
150
|
+
// MUST continue to iterate the results cursor and execute any further bulkWrite batches.
|
|
151
|
+
if (this.options.ordered) {
|
|
152
|
+
const error = new MongoClientBulkWriteError({
|
|
153
|
+
message: 'Mongo client ordered bulk write encountered a write error.'
|
|
154
|
+
});
|
|
155
|
+
error.writeErrors.set(document.idx + this.currentBatchOffset, {
|
|
156
|
+
code: document.code,
|
|
157
|
+
message: document.errmsg
|
|
158
|
+
});
|
|
159
|
+
error.partialResult = this.result;
|
|
160
|
+
throw error;
|
|
161
|
+
} else {
|
|
162
|
+
this.writeErrors.set(document.idx + this.currentBatchOffset, {
|
|
163
|
+
code: document.code,
|
|
164
|
+
message: document.errmsg
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (error instanceof MongoWriteConcernError) {
|
|
171
|
+
const result = error.result;
|
|
172
|
+
writeConcernErrorResult = {
|
|
173
|
+
insertedCount: result.nInserted,
|
|
174
|
+
upsertedCount: result.nUpserted,
|
|
175
|
+
matchedCount: result.nMatched,
|
|
176
|
+
modifiedCount: result.nModified,
|
|
177
|
+
deletedCount: result.nDeleted,
|
|
178
|
+
writeConcernError: result.writeConcernError
|
|
179
|
+
};
|
|
180
|
+
if (this.options.verboseResults && result.cursor.firstBatch) {
|
|
181
|
+
for (const document of result.cursor.firstBatch) {
|
|
182
|
+
if (document.ok === 1) {
|
|
183
|
+
this.processDocument(cursor, document);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
} finally {
|
|
191
|
+
// Update the counts from the cursor response.
|
|
192
|
+
if (cursor.response) {
|
|
193
|
+
const response = cursor.response;
|
|
194
|
+
this.incrementCounts(response);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Increment the batch offset.
|
|
198
|
+
this.currentBatchOffset += cursor.operations.length;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// If we have write concern errors ensure they are added.
|
|
202
|
+
if (writeConcernErrorResult) {
|
|
203
|
+
const writeConcernError = writeConcernErrorResult.writeConcernError as Document;
|
|
204
|
+
this.incrementCounts(writeConcernErrorResult);
|
|
205
|
+
this.writeConcernErrors.push({
|
|
206
|
+
code: writeConcernError.code,
|
|
207
|
+
message: writeConcernError.errmsg
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return this.result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Process an individual document in the results.
|
|
216
|
+
* @param cursor - The cursor.
|
|
217
|
+
* @param document - The document to process.
|
|
218
|
+
*/
|
|
219
|
+
private processDocument(cursor: ClientBulkWriteCursor, document: Document) {
|
|
220
|
+
// Get the corresponding operation from the command.
|
|
221
|
+
const operation = cursor.operations[document.idx];
|
|
222
|
+
// Handle insert results.
|
|
223
|
+
if ('insert' in operation) {
|
|
224
|
+
this.result.insertResults?.set(document.idx + this.currentBatchOffset, {
|
|
225
|
+
insertedId: operation.document._id
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
// Handle update results.
|
|
229
|
+
if ('update' in operation) {
|
|
230
|
+
const result: ClientUpdateResult = {
|
|
231
|
+
matchedCount: document.n,
|
|
232
|
+
modifiedCount: document.nModified ?? 0,
|
|
233
|
+
// Check if the bulk did actually upsert.
|
|
234
|
+
didUpsert: document.upserted != null
|
|
235
|
+
};
|
|
236
|
+
if (document.upserted) {
|
|
237
|
+
result.upsertedId = document.upserted._id;
|
|
238
|
+
}
|
|
239
|
+
this.result.updateResults?.set(document.idx + this.currentBatchOffset, result);
|
|
240
|
+
}
|
|
241
|
+
// Handle delete results.
|
|
242
|
+
if ('delete' in operation) {
|
|
243
|
+
this.result.deleteResults?.set(document.idx + this.currentBatchOffset, {
|
|
244
|
+
deletedCount: document.n
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Increment the result counts.
|
|
251
|
+
* @param document - The document with the results.
|
|
252
|
+
*/
|
|
253
|
+
private incrementCounts(document: Document) {
|
|
254
|
+
this.result.insertedCount += document.insertedCount;
|
|
255
|
+
this.result.upsertedCount += document.upsertedCount;
|
|
256
|
+
this.result.matchedCount += document.matchedCount;
|
|
257
|
+
this.result.modifiedCount += document.modifiedCount;
|
|
258
|
+
this.result.deletedCount += document.deletedCount;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -230,6 +230,10 @@ async function tryOperation<
|
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
if (operation.hasAspect(Aspect.COMMAND_BATCHING) && !operation.canRetryWrite) {
|
|
234
|
+
throw previousOperationError;
|
|
235
|
+
}
|
|
236
|
+
|
|
233
237
|
if (hasWriteAspect && !isRetryableWriteError(previousOperationError))
|
|
234
238
|
throw previousOperationError;
|
|
235
239
|
|
|
@@ -260,6 +264,10 @@ async function tryOperation<
|
|
|
260
264
|
}
|
|
261
265
|
|
|
262
266
|
try {
|
|
267
|
+
// If tries > 0 and we are command batching we need to reset the batch.
|
|
268
|
+
if (tries > 0 && operation.hasAspect(Aspect.COMMAND_BATCHING)) {
|
|
269
|
+
operation.resetBatch();
|
|
270
|
+
}
|
|
263
271
|
return await operation.execute(server, session);
|
|
264
272
|
} catch (operationError) {
|
|
265
273
|
if (!(operationError instanceof MongoError)) throw operationError;
|
package/src/operations/find.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Document } from '../bson';
|
|
2
2
|
import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';
|
|
3
3
|
import { MongoInvalidArgumentError } from '../error';
|
|
4
|
+
import { type ExplainOptions } from '../explain';
|
|
4
5
|
import { ReadConcern } from '../read_concern';
|
|
5
6
|
import type { Server } from '../sdam/server';
|
|
6
7
|
import type { ClientSession } from '../sessions';
|
|
@@ -15,7 +16,7 @@ import { Aspect, defineAspects, type Hint } from './operation';
|
|
|
15
16
|
*/
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
17
18
|
export interface FindOptions<TSchema extends Document = Document>
|
|
18
|
-
extends Omit<CommandOperationOptions, 'writeConcern'> {
|
|
19
|
+
extends Omit<CommandOperationOptions, 'writeConcern' | 'explain'> {
|
|
19
20
|
/** Sets the limit of documents returned in the query. */
|
|
20
21
|
limit?: number;
|
|
21
22
|
/** Set to sort the documents coming back from the query. Array of indexes, `[['a', 1]]` etc. */
|
|
@@ -63,6 +64,12 @@ export interface FindOptions<TSchema extends Document = Document>
|
|
|
63
64
|
* @deprecated Starting from MongoDB 4.4 this flag is not needed and will be ignored.
|
|
64
65
|
*/
|
|
65
66
|
oplogReplay?: boolean;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Specifies the verbosity mode for the explain output.
|
|
70
|
+
* @deprecated This API is deprecated in favor of `collection.find().explain()`.
|
|
71
|
+
*/
|
|
72
|
+
explain?: ExplainOptions['explain'];
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
/** @internal */
|