mongodb-ops 0.11.0 → 0.11.2
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/mongodb-ops.js +406 -381
- package/package.json +32 -28
- package/readme.md +130 -65
- package/test/fixtures/README.md +7 -0
- package/test/fixtures/vendor-orders-validator.json +224 -0
- package/test/mongodb-ops.test.js +160 -0
- package/test/mongodb-write-errors.test.js +89 -0
package/lib/mongodb-ops.js
CHANGED
|
@@ -1,381 +1,406 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const MongoClient = require('mongodb').MongoClient;
|
|
4
|
-
const ObjectID = require('mongodb').ObjectId;
|
|
5
|
-
|
|
6
|
-
class MongoDBOps {
|
|
7
|
-
/**
|
|
8
|
-
* @class
|
|
9
|
-
* @classdesc MongoDB operations - Note: writeConcern is not supported in this class
|
|
10
|
-
*
|
|
11
|
-
* @param {string} connString Database connection string
|
|
12
|
-
*/
|
|
13
|
-
constructor(connString) {
|
|
14
|
-
if (!connString) { throw new Error("missing-connection-string"); }
|
|
15
|
-
this.connString = connString;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Static method - Get ObjectId instance from string
|
|
20
|
-
*
|
|
21
|
-
* @param {string} id Object ID string
|
|
22
|
-
* @returns {object} ObjectId instance
|
|
23
|
-
*/
|
|
24
|
-
static getObjectId(id) { return new ObjectID(id); }
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Instance method - Get ObjectId instance from string
|
|
28
|
-
*
|
|
29
|
-
* @param {string} id Object ID string
|
|
30
|
-
* @returns {object} ObjectId instance
|
|
31
|
-
*/
|
|
32
|
-
getObjectId(id) { return new ObjectID(id); }
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Static method - Get DB client - It supports multiple db client with different connection string. Active db client will be reused for better performance
|
|
36
|
-
*
|
|
37
|
-
* @param {string} connString Database connection string
|
|
38
|
-
* @returns {promise} Promise with db client
|
|
39
|
-
*/
|
|
40
|
-
static async getDbClient(connString) {
|
|
41
|
-
if (!connString) { throw new Error("missing-connection-string"); }
|
|
42
|
-
|
|
43
|
-
if (!
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* @param {
|
|
111
|
-
* @param {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
*
|
|
168
|
-
* @
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* @param {
|
|
172
|
-
* @param {
|
|
173
|
-
* @
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
* @param {string} collectionName Collection name
|
|
238
|
-
* @param {object}
|
|
239
|
-
* @param {object}
|
|
240
|
-
* @param {
|
|
241
|
-
* @
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
* @
|
|
292
|
-
* @
|
|
293
|
-
* @
|
|
294
|
-
* @
|
|
295
|
-
* @
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MongoClient = require('mongodb').MongoClient;
|
|
4
|
+
const ObjectID = require('mongodb').ObjectId;
|
|
5
|
+
|
|
6
|
+
class MongoDBOps {
|
|
7
|
+
/**
|
|
8
|
+
* @class
|
|
9
|
+
* @classdesc MongoDB operations - Note: writeConcern is not supported in this class
|
|
10
|
+
*
|
|
11
|
+
* @param {string} connString Database connection string
|
|
12
|
+
*/
|
|
13
|
+
constructor(connString) {
|
|
14
|
+
if (!connString) { throw new Error("missing-connection-string"); }
|
|
15
|
+
this.connString = connString;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Static method - Get ObjectId instance from string
|
|
20
|
+
*
|
|
21
|
+
* @param {string} id Object ID string
|
|
22
|
+
* @returns {object} ObjectId instance
|
|
23
|
+
*/
|
|
24
|
+
static getObjectId(id) { return new ObjectID(id); }
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Instance method - Get ObjectId instance from string
|
|
28
|
+
*
|
|
29
|
+
* @param {string} id Object ID string
|
|
30
|
+
* @returns {object} ObjectId instance
|
|
31
|
+
*/
|
|
32
|
+
getObjectId(id) { return new ObjectID(id); }
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Static method - Get DB client - It supports multiple db client with different connection string. Active db client will be reused for better performance
|
|
36
|
+
*
|
|
37
|
+
* @param {string} connString Database connection string
|
|
38
|
+
* @returns {promise} Promise with db client
|
|
39
|
+
*/
|
|
40
|
+
static async getDbClient(connString) {
|
|
41
|
+
if (!connString) { throw new Error("missing-connection-string"); }
|
|
42
|
+
|
|
43
|
+
if (!(MongoDBOps.dbClients instanceof Map)) { MongoDBOps.dbClients = new Map(); }
|
|
44
|
+
|
|
45
|
+
let clientPromise = MongoDBOps.dbClients.get(connString);
|
|
46
|
+
if (!clientPromise) {
|
|
47
|
+
const options = Object.assign(
|
|
48
|
+
{ serverSelectionTimeoutMS: 8000, retryWrites: true, retryReads: true },
|
|
49
|
+
MongoDBOps.clientOptions || {}
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
clientPromise = MongoClient.connect(connString, options).catch((err) => {
|
|
53
|
+
if (MongoDBOps.dbClients.get(connString) === clientPromise) {
|
|
54
|
+
MongoDBOps.dbClients.delete(connString);
|
|
55
|
+
}
|
|
56
|
+
throw err;
|
|
57
|
+
});
|
|
58
|
+
MongoDBOps.dbClients.set(connString, clientPromise);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return clientPromise;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Static method - Close database connection
|
|
66
|
+
* @returns {promise}
|
|
67
|
+
*/
|
|
68
|
+
static async closeDBConn() {
|
|
69
|
+
if (MongoDBOps.dbClients instanceof Map) {
|
|
70
|
+
const clientPromises = Array.from(MongoDBOps.dbClients.values());
|
|
71
|
+
MongoDBOps.dbClients.clear();
|
|
72
|
+
|
|
73
|
+
for (const clientPromise of clientPromises) {
|
|
74
|
+
try {
|
|
75
|
+
const client = await clientPromise;
|
|
76
|
+
await client.close();
|
|
77
|
+
} catch {
|
|
78
|
+
// Failed or already-evicted connection attempts do not need separate cleanup.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (Array.isArray(MongoDBOps.dbClientList)) {
|
|
84
|
+
const legacyClients = MongoDBOps.dbClientList;
|
|
85
|
+
MongoDBOps.dbClientList = [];
|
|
86
|
+
|
|
87
|
+
for (const item of legacyClients) {
|
|
88
|
+
try {
|
|
89
|
+
await item.close();
|
|
90
|
+
} catch {
|
|
91
|
+
// Ignore stale legacy clients from older mixed-version processes.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Promise.resolve();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Instance method - Close database connection
|
|
101
|
+
* @returns {promise}
|
|
102
|
+
*/
|
|
103
|
+
async closeDBConn() {
|
|
104
|
+
return Promise.resolve(await MongoDBOps.closeDBConn());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Static method - Get estimated document count of a collection
|
|
109
|
+
*
|
|
110
|
+
* @param {string} collectionName Collection Name
|
|
111
|
+
* @param {string} connString Database connection string
|
|
112
|
+
*/
|
|
113
|
+
static async getCollectionCount(collectionName, connString) {
|
|
114
|
+
const db = (await MongoDBOps.getDbClient(connString)).db();
|
|
115
|
+
return Promise.resolve(await db.collection(collectionName).estimatedDocumentCount());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Instance method - Get estimated document count of a collection
|
|
120
|
+
*
|
|
121
|
+
* @param {string} collectionName Collection Name
|
|
122
|
+
* @param {string} connString Database connection string
|
|
123
|
+
*/
|
|
124
|
+
async getCollectionCount(collectionName) {
|
|
125
|
+
return Promise.resolve(await MongoDBOps.getData(collectionName, this.connString));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Static method - Get documents from MongoDB
|
|
130
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/}
|
|
131
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.aggregate/}
|
|
132
|
+
*
|
|
133
|
+
* @param {string} collectionName Collection name
|
|
134
|
+
* @param {object} [queryExp] Query Specifies selection filter using query operators - {@link https://docs.mongodb.com/manual/reference/operator/}
|
|
135
|
+
* @param {boolean} [isAggregate=false] Set true to use the aggregation
|
|
136
|
+
* @param {object} [projection] Projection {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#find-projection}
|
|
137
|
+
* @param {object} [sort] Sort {@link https://docs.mongodb.com/manual/reference/method/cursor.sort/#cursor.sort}
|
|
138
|
+
* @param {object} [pagination] Pagination `E.g., { startIndex: 11, endIndex: 20 }`
|
|
139
|
+
* @param {boolean} [isGetCount=false] Set true to get the number of doc count based on the queryExp
|
|
140
|
+
* @param {string} connString Database connection string
|
|
141
|
+
* @param {object} [collation] Collation {@link https://www.mongodb.com/docs/manual/reference/collation/#std-label-collation-document-fields}
|
|
142
|
+
* @param {object} [options] Aggregate options {@link https://www.mongodb.com/docs/manual/reference/method/db.collection.aggregate/}
|
|
143
|
+
* @returns {promise} Promise with object array
|
|
144
|
+
*/
|
|
145
|
+
static async getData(collectionName, queryExp, isAggregate = false, projection, sort, pagination, isGetCount = false, connString, collation, options) {
|
|
146
|
+
const db = (await MongoDBOps.getDbClient(connString)).db();
|
|
147
|
+
|
|
148
|
+
if (isAggregate) { return Promise.resolve(await db.collection(collectionName).aggregate(queryExp, options).toArray()); }
|
|
149
|
+
|
|
150
|
+
queryExp = queryExp || {};
|
|
151
|
+
if (isGetCount) { return Promise.resolve(await db.collection(collectionName).countDocuments(queryExp)); }
|
|
152
|
+
|
|
153
|
+
const { skip, limit } = parsePagination(pagination);
|
|
154
|
+
if (limit < 1) { return Promise.resolve([]); }
|
|
155
|
+
|
|
156
|
+
projection = { projection: projection || {} };
|
|
157
|
+
|
|
158
|
+
let data = db.collection(collectionName).find(queryExp, projection);
|
|
159
|
+
if (sort) { data = data.sort(sort); }
|
|
160
|
+
if (pagination) { data = data.skip(skip).limit(limit); }
|
|
161
|
+
if (collation) { data = data.collation(collation); }
|
|
162
|
+
|
|
163
|
+
return Promise.resolve(await data.toArray());
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Instance method - Get documents from MongoDB
|
|
168
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/}
|
|
169
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.aggregate/}
|
|
170
|
+
*
|
|
171
|
+
* @param {string} collectionName Collection name
|
|
172
|
+
* @param {object} [queryExp] Query Specifies selection filter using query operators - {@link https://docs.mongodb.com/manual/reference/operator/}
|
|
173
|
+
* @param {boolean} [isAggregate=false] Set true to use the aggregation
|
|
174
|
+
* @param {object} [projection] Projection {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#find-projection}
|
|
175
|
+
* @param {object} [sort] Sort {@link https://docs.mongodb.com/manual/reference/method/cursor.sort/#cursor.sort}
|
|
176
|
+
* @param {object} [pagination] Pagination `E.g., { startIndex: 11, endIndex: 20 }`
|
|
177
|
+
* @param {boolean} [isGetCount=false] Set true to get the number of doc count based on the queryExp
|
|
178
|
+
* @param {object} [collation] Collation {@link https://www.mongodb.com/docs/manual/reference/collation/#std-label-collation-document-fields}
|
|
179
|
+
* @param {object} [options] Aggregate options {@link https://www.mongodb.com/docs/manual/reference/method/db.collection.aggregate/}
|
|
180
|
+
* @returns {promise} Promise with object array
|
|
181
|
+
*/
|
|
182
|
+
async getData(collectionName, queryExp, isAggregate, projection, sort, pagination, isGetCount, collation, options) {
|
|
183
|
+
return Promise.resolve(await MongoDBOps.getData(collectionName, queryExp, isAggregate, projection, sort, pagination, isGetCount, this.connString, collation, options));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Static method - Use altas search at MongoDB
|
|
188
|
+
* {@link https://www.mongodb.com/docs/atlas/atlas-search/}
|
|
189
|
+
*
|
|
190
|
+
* @param {string} connString Database connection string
|
|
191
|
+
* @param {string} collectionName Collection name
|
|
192
|
+
* @param {object} search $search object - {@link https://www.mongodb.com/docs/atlas/atlas-search/query-syntax/}
|
|
193
|
+
* @param {object} [obj]
|
|
194
|
+
* @param {object} [obj.projection] Projection {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#find-projection}
|
|
195
|
+
* @param {object} [obj.sort] Sort {@link https://docs.mongodb.com/manual/reference/method/cursor.sort/#cursor.sort}
|
|
196
|
+
* @param {object} [obj.pagination] Pagination `E.g., { startIndex: 11, endIndex: 20 }`
|
|
197
|
+
* @param {boolean} [isGetCount=true] Set true to get the number of total matching docs and current page number
|
|
198
|
+
* @returns {promise} Promise with object or object array
|
|
199
|
+
*/
|
|
200
|
+
static async search(connString, collectionName, search, { projection, sort, pagination }={}, isGetCount = true) {
|
|
201
|
+
if ([connString, collectionName, search].includes(undefined)) { return Promise.reject("Connection string, collection name and search cannot be undefined"); }
|
|
202
|
+
|
|
203
|
+
const { skip, limit } = parsePagination(pagination);
|
|
204
|
+
if (limit < 1) { return Promise.resolve([]); }
|
|
205
|
+
|
|
206
|
+
const payload = [
|
|
207
|
+
{ $search: search },
|
|
208
|
+
{ $addFields: { score: { $meta: "searchScore" }}},
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
if (projection) { payload.push({ $project: projection }); }
|
|
212
|
+
if (sort) { payload.push({ $sort: sort }); }
|
|
213
|
+
|
|
214
|
+
const skipLimit = [];
|
|
215
|
+
if (skip) { skipLimit.push({ $skip: skip }); }
|
|
216
|
+
if (limit) { skipLimit.push({ $limit: limit }); }
|
|
217
|
+
|
|
218
|
+
if (isGetCount) {
|
|
219
|
+
payload.push({
|
|
220
|
+
$facet: {
|
|
221
|
+
metadata: [{ $count: "total" }, { $addFields: { page: Math.ceil((skip + 1) / limit) }}],
|
|
222
|
+
data: skipLimit,
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
else { payload.push(...skipLimit); }
|
|
227
|
+
|
|
228
|
+
const result = await MongoDBOps.getData(collectionName, payload, true, undefined, undefined, undefined, undefined, connString);
|
|
229
|
+
|
|
230
|
+
return Promise.resolve(isGetCount ? result[0] : result);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Instance method - Use altas search at MongoDB
|
|
235
|
+
* {@link https://www.mongodb.com/docs/atlas/atlas-search/}
|
|
236
|
+
*
|
|
237
|
+
* @param {string} collectionName Collection name
|
|
238
|
+
* @param {object} search $search object - {@link https://www.mongodb.com/docs/atlas/atlas-search/query-syntax/}
|
|
239
|
+
* @param {object} [obj]
|
|
240
|
+
* @param {object} [obj.projection] Projection {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#find-projection}
|
|
241
|
+
* @param {object} [obj.sort] Sort {@link https://docs.mongodb.com/manual/reference/method/cursor.sort/#cursor.sort}
|
|
242
|
+
* @param {object} [obj.pagination] Pagination `E.g., { startIndex: 11, endIndex: 20 }`
|
|
243
|
+
* @param {boolean} [isGetCount=true] Set true to get the number of total matching docs and current page number
|
|
244
|
+
* @returns {promise} Promise with object or object array
|
|
245
|
+
*/
|
|
246
|
+
async search(collectionName, search, { projection, sort, pagination }={}, isGetCount = true) {
|
|
247
|
+
return Promise.resolve(await MongoDBOps.search(this.connString, collectionName, search, { projection, sort, pagination }, isGetCount));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Static method - Write document to MongoDB
|
|
252
|
+
*
|
|
253
|
+
* References:
|
|
254
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.insertOne/}
|
|
255
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/}
|
|
256
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/}
|
|
257
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/}
|
|
258
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.deleteOne/}
|
|
259
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.deleteMany/}
|
|
260
|
+
*
|
|
261
|
+
* @param {string} type Write type - insertOne, replaceOne, updateOne, updateMany, deleteOne, deleteMany
|
|
262
|
+
* @param {string} collectionName Collection name
|
|
263
|
+
* @param {object} doc Data document
|
|
264
|
+
* @param {object} filter Query filter {@link https://docs.mongodb.com/manual/core/document/#document-query-filter}
|
|
265
|
+
* @param {string} connString Database connection string
|
|
266
|
+
* @returns {promise}
|
|
267
|
+
*/
|
|
268
|
+
static async writeData(type, collectionName, doc, filter, connString) {
|
|
269
|
+
try {
|
|
270
|
+
const db = (await MongoDBOps.getDbClient(connString)).db();
|
|
271
|
+
|
|
272
|
+
let result;
|
|
273
|
+
switch(type) {
|
|
274
|
+
case "insertOne": result = await db.collection(collectionName).insertOne(doc); break;
|
|
275
|
+
case "replaceOne": result = await db.collection(collectionName).replaceOne(filter, doc); break;
|
|
276
|
+
case "updateOne": result = await db.collection(collectionName).updateOne(filter, doc); break;
|
|
277
|
+
case "updateMany": result = await db.collection(collectionName).updateMany(filter, doc); break;
|
|
278
|
+
case "deleteOne": result = await db.collection(collectionName).deleteOne(filter); break;
|
|
279
|
+
case "deleteMany": result = await db.collection(collectionName).deleteMany(filter); break;
|
|
280
|
+
default: throw new Error("invalid-writeData-type");
|
|
281
|
+
}
|
|
282
|
+
return Promise.resolve(result);
|
|
283
|
+
}
|
|
284
|
+
catch (err) { return Promise.reject(err); }
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Instance method - Write document to MongoDB
|
|
289
|
+
*
|
|
290
|
+
* References:
|
|
291
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.insertOne/}
|
|
292
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/}
|
|
293
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/}
|
|
294
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/}
|
|
295
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.deleteOne/}
|
|
296
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.deleteMany/}
|
|
297
|
+
*
|
|
298
|
+
* @param {string} type Write type - insertOne, replaceOne, updateOne, updateMany, deleteOne, deleteMany
|
|
299
|
+
* @param {string} collectionName Collection name
|
|
300
|
+
* @param {object} doc Data document
|
|
301
|
+
* @param {object} filter Query filter {@link https://docs.mongodb.com/manual/core/document/#document-query-filter}
|
|
302
|
+
* @returns {promise}
|
|
303
|
+
*/
|
|
304
|
+
async writeData(type, collectionName, doc, filter) {
|
|
305
|
+
return Promise.resolve(await MongoDBOps.writeData(type, collectionName, doc, filter, this.connString));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Static method - Write document to MongoDB via BulkOps / BulkWrite
|
|
310
|
+
*
|
|
311
|
+
* References:
|
|
312
|
+
* {@link https://mongodb.github.io/node-mongodb-native/3.6/api/BulkOperationBase.html}
|
|
313
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/}
|
|
314
|
+
*
|
|
315
|
+
* @param {string} type Write type - insertBulk, replaceBulk, updateBulk, allBulk
|
|
316
|
+
* @param {string} collectionName Collection name
|
|
317
|
+
* @param {Array} docs Data documents array
|
|
318
|
+
* @param {boolean} [ordered=false] Set true to use ordered bulkWrite
|
|
319
|
+
* @param {string} connString Database connection string
|
|
320
|
+
* @returns {promise}
|
|
321
|
+
*/
|
|
322
|
+
static async writeBulkData(type, collectionName, docs, ordered = false, connString) {
|
|
323
|
+
try {
|
|
324
|
+
const db = (await MongoDBOps.getDbClient(connString)).db();
|
|
325
|
+
|
|
326
|
+
let result;
|
|
327
|
+
switch(type) {
|
|
328
|
+
case "insertBulk":
|
|
329
|
+
for (let i = 0; i < docs.length; ++i) { docs[i] = { insertOne: { "document": docs[i] }}; }
|
|
330
|
+
break;
|
|
331
|
+
case "replaceBulk":
|
|
332
|
+
// doc = {
|
|
333
|
+
// "filter": <document>,
|
|
334
|
+
// "replacement": <document>,
|
|
335
|
+
// "upsert": <boolean>,
|
|
336
|
+
// "collation": <document>,
|
|
337
|
+
// "hint": <document|string>
|
|
338
|
+
// }
|
|
339
|
+
for (let i = 0; i < docs.length; ++i) { docs[i] = { replaceOne: docs[i] }; }
|
|
340
|
+
break;
|
|
341
|
+
case "updateBulk":
|
|
342
|
+
// doc = {
|
|
343
|
+
// "filter": <document>,
|
|
344
|
+
// "update": <document or pipeline>,
|
|
345
|
+
// "upsert": <boolean>,
|
|
346
|
+
// "collation": <document>,
|
|
347
|
+
// "arrayFilters": [ <filterdocument1>, ... ],
|
|
348
|
+
// "hint": <document|string>
|
|
349
|
+
// }
|
|
350
|
+
for (let i = 0; i < docs.length; ++i) { docs[i] = { updateOne: docs[i] }; }
|
|
351
|
+
break;
|
|
352
|
+
case "deleteBulk":
|
|
353
|
+
// doc = {
|
|
354
|
+
// "filter": <document>,
|
|
355
|
+
// "collation": <document>
|
|
356
|
+
// }
|
|
357
|
+
for (let i = 0; i < docs.length; ++i) { docs[i] = { deleteOne: docs[i] }; }
|
|
358
|
+
break;
|
|
359
|
+
case "allBulk":
|
|
360
|
+
// allowed bulkWrite operations include insertOne, replaceOne, updateOne, updateMany, deleteOne, deleteMany
|
|
361
|
+
break;
|
|
362
|
+
default: throw new Error("invalid-writeBulkData-type");
|
|
363
|
+
}
|
|
364
|
+
result = await db.collection(collectionName).bulkWrite(docs, { ordered: ordered });
|
|
365
|
+
return Promise.resolve(result);
|
|
366
|
+
}
|
|
367
|
+
catch (err) { return Promise.reject(err); }
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Instance method - Write document to MongoDB via BulkOps / BulkWrite
|
|
372
|
+
*
|
|
373
|
+
* References:
|
|
374
|
+
* {@link https://mongodb.github.io/node-mongodb-native/3.6/api/BulkOperationBase.html}
|
|
375
|
+
* {@link https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/}
|
|
376
|
+
*
|
|
377
|
+
* @param {string} type Write type - insertBulk, replaceBulk, updateBulk, allBulk
|
|
378
|
+
* @param {string} collectionName Collection name
|
|
379
|
+
* @param {Array} docs Data documents array
|
|
380
|
+
* @param {boolean} [ordered=false] Set true to use ordered bulkWrite
|
|
381
|
+
* @returns {promise}
|
|
382
|
+
*/
|
|
383
|
+
async writeBulkData(type, collectionName, docs, ordered = false) {
|
|
384
|
+
return Promise.resolve(await MongoDBOps.writeBulkData(type, collectionName, docs, ordered, this.connString));
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
module.exports = MongoDBOps;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Parse the pagaintion and return skip and limit values
|
|
392
|
+
*
|
|
393
|
+
* @param {object} obj
|
|
394
|
+
* @param {number} [obj.startIndex] Start index
|
|
395
|
+
* @param {number} [obj.endIndex] Start index
|
|
396
|
+
* @returns {object} Object with skip and limit values
|
|
397
|
+
*/
|
|
398
|
+
const parsePagination = ({ startIndex, endIndex }={})=> {
|
|
399
|
+
startIndex = +startIndex; endIndex = +endIndex;
|
|
400
|
+
startIndex = startIndex < 1 ? 1 : startIndex;
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
skip: Number.isInteger(startIndex) ? startIndex - 1 : undefined,
|
|
404
|
+
limit: Number.isInteger(startIndex) && Number.isInteger(endIndex) ? ((endIndex - startIndex + 1) < 0 ? 0 : endIndex - startIndex + 1) : undefined
|
|
405
|
+
};
|
|
406
|
+
}
|