w-orm-mongodb 1.1.37 → 1.1.39
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/README.md +447 -288
- package/dist/w-orm-mongodb.umd.js +2 -2
- package/dist/w-orm-mongodb.umd.js.map +1 -1
- package/docs/WOrmMongodb.html +221 -37
- package/docs/WOrmMongodb.mjs.html +1265 -829
- package/docs/index.html +2 -2
- package/g-basic.mjs +16 -6
- package/g-gfs.mjs +102 -102
- package/g-unique.mjs +66 -0
- package/package.json +2 -3
- package/script.txt +0 -1
- package/src/WOrmMongodb.mjs +1263 -827
- package/test/api-basic.test.mjs +1200 -0
- package/test/api-gfs.test.mjs +574 -0
- package/test/lib/api-setup.mjs +142 -0
- package/test/basic.test.mjs +0 -348
- package/test/gfs.test.mjs +0 -172
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<nav >
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WOrmMongodb.html">WOrmMongodb</a><ul class='methods'><li data-type='method'><a href="WOrmMongodb.html#.del">del</a></li><li data-type='method'><a href="WOrmMongodb.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmMongodb.html#.delAllGfs">delAllGfs</a></li><li data-type='method'><a href="WOrmMongodb.html#.delGfs">delGfs</a></li><li data-type='method'><a href="WOrmMongodb.html#.insert">insert</a></li><li data-type='method'><a href="WOrmMongodb.html#.insertGfs">insertGfs</a></li><li data-type='method'><a href="WOrmMongodb.html#.save">save</a></li><li data-type='method'><a href="WOrmMongodb.html#.select">select</a></li><li data-type='method'><a href="WOrmMongodb.html#.
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WOrmMongodb.html">WOrmMongodb</a><ul class='methods'><li data-type='method'><a href="WOrmMongodb.html#.del">del</a></li><li data-type='method'><a href="WOrmMongodb.html#.delAll">delAll</a></li><li data-type='method'><a href="WOrmMongodb.html#.delAllGfs">delAllGfs</a></li><li data-type='method'><a href="WOrmMongodb.html#.delGfs">delGfs</a></li><li data-type='method'><a href="WOrmMongodb.html#.insert">insert</a></li><li data-type='method'><a href="WOrmMongodb.html#.insertGfs">insertGfs</a></li><li data-type='method'><a href="WOrmMongodb.html#.save">save</a></li><li data-type='method'><a href="WOrmMongodb.html#.select">select</a></li><li data-type='method'><a href="WOrmMongodb.html#.selectByPk">selectByPk</a></li><li data-type='method'><a href="WOrmMongodb.html#.selectByPkGfs">selectByPkGfs</a></li></ul></li></ul>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -45,833 +45,1269 @@
|
|
|
45
45
|
|
|
46
46
|
<section>
|
|
47
47
|
<article>
|
|
48
|
-
<pre class="prettyprint source linenums"><code>import events from 'events'
|
|
49
|
-
import mongodb from 'mongodb'
|
|
50
|
-
import stream from 'stream'
|
|
51
|
-
import cloneDeep from 'lodash-es/cloneDeep.js'
|
|
52
|
-
import
|
|
53
|
-
import
|
|
54
|
-
import
|
|
55
|
-
import
|
|
56
|
-
import
|
|
57
|
-
import
|
|
58
|
-
import
|
|
59
|
-
import
|
|
60
|
-
import
|
|
61
|
-
import
|
|
62
|
-
import
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* @
|
|
76
|
-
* @param {
|
|
77
|
-
* @param {String} [opt.
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
let
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
catch (err) {
|
|
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
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
client
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
//
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
//
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
//
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
//
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
48
|
+
<pre class="prettyprint source linenums"><code>import events from 'events'
|
|
49
|
+
import mongodb from 'mongodb'
|
|
50
|
+
import stream from 'stream'
|
|
51
|
+
import cloneDeep from 'lodash-es/cloneDeep.js'
|
|
52
|
+
import every from 'lodash-es/every.js'
|
|
53
|
+
import get from 'lodash-es/get.js'
|
|
54
|
+
import map from 'lodash-es/map.js'
|
|
55
|
+
import omit from 'lodash-es/omit.js'
|
|
56
|
+
import size from 'lodash-es/size.js'
|
|
57
|
+
import genPm from 'wsemi/src/genPm.mjs'
|
|
58
|
+
import genID from 'wsemi/src/genID.mjs'
|
|
59
|
+
import isestr from 'wsemi/src/isestr.mjs'
|
|
60
|
+
import isarr from 'wsemi/src/isarr.mjs'
|
|
61
|
+
import isearr from 'wsemi/src/isearr.mjs'
|
|
62
|
+
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
63
|
+
import isu8arr from 'wsemi/src/isu8arr.mjs'
|
|
64
|
+
import pmSeries from 'wsemi/src/pmSeries.mjs'
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 操作資料庫(MongoDB)
|
|
69
|
+
*
|
|
70
|
+
* 本套件之主鍵欄位固定為id,尚未支援由呼叫端指定。
|
|
71
|
+
* id為無業務語義之識別碼,故insert與save於輸入未帶有效id時自動補值;del不補值。
|
|
72
|
+
*
|
|
73
|
+
* @class
|
|
74
|
+
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
75
|
+
* @param {String} [opt.url='mongodb://127.0.0.1:27017'] 輸入連接資料庫字串,預設'mongodb://127.0.0.1:27017'
|
|
76
|
+
* @param {String} [opt.db='worm'] 輸入使用資料庫名稱字串,預設'worm'
|
|
77
|
+
* @param {String} [opt.cl='test'] 輸入使用資料表名稱字串,預設'test'
|
|
78
|
+
* @returns {Object} 回傳操作資料庫物件,各事件功能詳見說明
|
|
79
|
+
*/
|
|
80
|
+
function WOrmMongodb(opt = {}) {
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
//default
|
|
84
|
+
if (!opt.url) {
|
|
85
|
+
opt.url = 'mongodb://127.0.0.1:27017'
|
|
86
|
+
}
|
|
87
|
+
if (!opt.db) {
|
|
88
|
+
opt.db = 'worm'
|
|
89
|
+
}
|
|
90
|
+
if (!opt.cl) {
|
|
91
|
+
opt.cl = 'test'
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
//_indexReady, 唯一索引只須建立一次, 以旗標記錄避免每次操作皆多一次round-trip
|
|
96
|
+
let _indexReady = false
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
//_indexGfsReady, GridFS之唯一索引亦只須建立一次
|
|
100
|
+
let _indexGfsReady = false
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
//ee
|
|
104
|
+
let ee = new events.EventEmitter()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
//MongoClient
|
|
108
|
+
let MongoClient = mongodb.MongoClient
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 取錯誤訊息字串,供逐筆結果之err欄位使用
|
|
113
|
+
*
|
|
114
|
+
* @ignore
|
|
115
|
+
* @param {Error|String} err 輸入錯誤物件或字串
|
|
116
|
+
* @returns {String} 回傳錯誤訊息字串
|
|
117
|
+
*/
|
|
118
|
+
function genErrMsg(err) {
|
|
119
|
+
|
|
120
|
+
//message
|
|
121
|
+
let message = get(err, 'message')
|
|
122
|
+
if (isestr(message)) {
|
|
123
|
+
return message
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return String(err)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 發出change事件,訂閱函數拋錯不得影響本次操作之結果,故另包try並自行吞掉
|
|
132
|
+
*
|
|
133
|
+
* @ignore
|
|
134
|
+
* @param {String} mode 輸入操作模式字串
|
|
135
|
+
* @param {Array|null} data 輸入本次操作之數據
|
|
136
|
+
* @param {Object|Array} res 輸入本次操作之結果
|
|
137
|
+
* @returns {undefined} 無回傳值
|
|
138
|
+
*/
|
|
139
|
+
function emitChange(mode, data, res) {
|
|
140
|
+
try {
|
|
141
|
+
ee.emit('change', mode, data, res)
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
console.log(err)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 判定是否為唯一索引重複鍵錯誤(11000),批次插入時須全部寫入錯誤皆為重複鍵才算
|
|
151
|
+
*
|
|
152
|
+
* @ignore
|
|
153
|
+
* @param {Error} err 輸入錯誤物件
|
|
154
|
+
* @returns {Boolean} 回傳是否為重複鍵錯誤布林值
|
|
155
|
+
*/
|
|
156
|
+
function isDupKeyError(err) {
|
|
157
|
+
|
|
158
|
+
//writeErrors, 批次寫入時各筆錯誤置於writeErrors內
|
|
159
|
+
let writeErrors = get(err, 'writeErrors')
|
|
160
|
+
if (isearr(writeErrors)) {
|
|
161
|
+
return every(writeErrors, function(v) {
|
|
162
|
+
return get(v, 'code') === 11000 || get(v, 'err.code') === 11000
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return get(err, 'code') === 11000
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 於id欄位建立唯一索引,令[檢查id是否存在]與[寫入]得由MongoDB於單一文件操作內原子完成
|
|
172
|
+
* 註: 若既有資料表內已存在重複id,建立索引會失敗並將錯誤往外拋,須先自行清除重複數據,
|
|
173
|
+
* 此錯誤影響本次操作之全部數據,屬整批性錯誤,故不轉為逐筆之ok為0
|
|
174
|
+
*
|
|
175
|
+
* @ignore
|
|
176
|
+
* @param {Object} collection 輸入資料表物件
|
|
177
|
+
* @returns {Promise} 回傳Promise,resolve回傳undefined,reject回傳錯誤訊息
|
|
178
|
+
*/
|
|
179
|
+
async function ensureIndex(collection) {
|
|
180
|
+
|
|
181
|
+
//check
|
|
182
|
+
if (_indexReady) {
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//createIndex, 已存在同樣索引時MongoDB不會重建亦不報錯
|
|
187
|
+
await collection.createIndex({ id: 1 }, { unique: true })
|
|
188
|
+
|
|
189
|
+
//_indexReady
|
|
190
|
+
_indexReady = true
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 使用GridFS,於filename欄位建立唯一索引,令[檢查id是否存在]與[寫入]由MongoDB判定而非由本套件先讀後寫
|
|
197
|
+
* 註: GridFS以files資料表之filename存放id,其本身不具唯一性,須另建唯一索引方能達成[已存在則跳過];
|
|
198
|
+
* 若既有資料表內已存在重複id,建立索引會失敗並將錯誤往外拋,須先自行清除重複數據
|
|
199
|
+
*
|
|
200
|
+
* @ignore
|
|
201
|
+
* @param {Object} database 輸入資料庫物件
|
|
202
|
+
* @returns {Promise} 回傳Promise,resolve回傳undefined,reject回傳錯誤訊息
|
|
203
|
+
*/
|
|
204
|
+
async function ensureIndexGfs(database) {
|
|
205
|
+
|
|
206
|
+
//check
|
|
207
|
+
if (_indexGfsReady) {
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
//createIndex, 已存在同樣索引時MongoDB不會重建亦不報錯
|
|
212
|
+
await database.collection(`${opt.cl}.files`).createIndex({ filename: 1 }, { unique: true })
|
|
213
|
+
|
|
214
|
+
//_indexGfsReady
|
|
215
|
+
_indexGfsReady = true
|
|
216
|
+
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 使用GridFS,上傳單筆數據
|
|
222
|
+
* 註: 已存在同一id時MongoDB以重複鍵錯誤拒絕,惟chunks於files文件之前即已寫入,
|
|
223
|
+
* 故須以files_id清除該次所遺留之chunks,避免累積孤兒數據
|
|
224
|
+
*
|
|
225
|
+
* @ignore
|
|
226
|
+
* @param {Object} bucket 輸入GridFSBucket物件
|
|
227
|
+
* @param {Object} clChunks 輸入GridFS之chunks資料表物件
|
|
228
|
+
* @param {String} id 輸入id字串
|
|
229
|
+
* @param {Uint8Array} u8a 輸入數據Uint8Array
|
|
230
|
+
* @returns {Promise} 回傳Promise,resolve回傳本次是否已插入布林值,reject回傳錯誤訊息
|
|
231
|
+
*/
|
|
232
|
+
function _uploadGfs(bucket, clChunks, id, u8a) {
|
|
233
|
+
|
|
234
|
+
//pm
|
|
235
|
+
let pm = genPm()
|
|
236
|
+
|
|
237
|
+
//ws, files_id於finish前即可取得, 供清除孤兒chunks用
|
|
238
|
+
let ws = bucket.openUploadStream(id)
|
|
239
|
+
let fid = ws.id
|
|
240
|
+
|
|
241
|
+
//stream
|
|
242
|
+
let sm = new stream.Readable()
|
|
243
|
+
sm._read = () => {}
|
|
244
|
+
sm.push(Buffer.from(u8a))
|
|
245
|
+
sm.push(null)
|
|
246
|
+
sm.pipe(ws) //pipe是接bucket的Writable, 所以會監聽finish
|
|
247
|
+
.on('error', function(err) {
|
|
248
|
+
|
|
249
|
+
//check, 重複鍵錯誤表示已存在同一id而跳過, 屬正常結果而非錯誤
|
|
250
|
+
if (!isDupKeyError(err)) {
|
|
251
|
+
pm.reject(err)
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
//清除本次所遺留之孤兒chunks
|
|
256
|
+
clChunks.deleteMany({ files_id: fid })
|
|
257
|
+
.then(function() {
|
|
258
|
+
pm.resolve(false)
|
|
259
|
+
})
|
|
260
|
+
.catch(function(err) {
|
|
261
|
+
pm.reject(err)
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
})
|
|
265
|
+
.on('finish', function() {
|
|
266
|
+
|
|
267
|
+
//resolve
|
|
268
|
+
pm.resolve(true)
|
|
269
|
+
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
return pm
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* 查詢數據
|
|
278
|
+
*
|
|
279
|
+
* @memberOf WOrmMongodb
|
|
280
|
+
* @param {Object} [find={}] 輸入查詢條件物件
|
|
281
|
+
* @returns {Promise} 回傳Promise,resolve回傳數據陣列,無符合數據回傳空陣列,reject回傳錯誤訊息
|
|
282
|
+
*/
|
|
283
|
+
async function select(find = {}) {
|
|
284
|
+
let isErr = false
|
|
285
|
+
|
|
286
|
+
//client
|
|
287
|
+
let client = new MongoClient(opt.url)
|
|
288
|
+
|
|
289
|
+
//res
|
|
290
|
+
let res = null
|
|
291
|
+
try {
|
|
292
|
+
|
|
293
|
+
//database, collection
|
|
294
|
+
let database = client.db(opt.db)
|
|
295
|
+
let collection = database.collection(opt.cl)
|
|
296
|
+
|
|
297
|
+
//find
|
|
298
|
+
let cursor = collection.find(find)
|
|
299
|
+
|
|
300
|
+
//toArray
|
|
301
|
+
res = await cursor.toArray()
|
|
302
|
+
|
|
303
|
+
//omit, 去除資料庫內部欄位_id, 令回傳欄位與寫入時所給者一致
|
|
304
|
+
res = map(res, function(v) {
|
|
305
|
+
v = omit(v, '_id')
|
|
306
|
+
return v
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
isErr = true
|
|
312
|
+
res = err
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
await client.close()
|
|
316
|
+
client = null
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (isErr) {
|
|
320
|
+
return Promise.reject(res)
|
|
321
|
+
}
|
|
322
|
+
return res
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* 由主鍵查詢單筆數據,因由MongoDB查找且僅回傳單筆,不需如select提取全部符合數據再處理,故數據量大時效能較佳
|
|
328
|
+
* 註: 本套件之主鍵欄位固定為id,尚未支援由呼叫端指定
|
|
329
|
+
* 註: 本函數不得有副作用,故不建立唯一索引
|
|
330
|
+
*
|
|
331
|
+
* @memberOf WOrmMongodb
|
|
332
|
+
* @param {String} pk 輸入主鍵值字串,即數據之id
|
|
333
|
+
* @returns {Promise} 回傳Promise,resolve回傳數據物件,若無此主鍵或主鍵值無效則回傳null,reject回傳錯誤訊息
|
|
334
|
+
*/
|
|
335
|
+
async function selectByPk(pk) {
|
|
336
|
+
let isErr = false
|
|
337
|
+
|
|
338
|
+
//check
|
|
339
|
+
if (!isestr(pk)) {
|
|
340
|
+
//未給有效主鍵值視為查無數據, 判定基準與insert、save、del內對id之認定一致
|
|
341
|
+
return null
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
//client
|
|
345
|
+
let client = new MongoClient(opt.url)
|
|
346
|
+
|
|
347
|
+
//res
|
|
348
|
+
let res = null
|
|
349
|
+
try {
|
|
350
|
+
|
|
351
|
+
//database, collection
|
|
352
|
+
let database = client.db(opt.db)
|
|
353
|
+
let collection = database.collection(opt.cl)
|
|
354
|
+
|
|
355
|
+
//findOne, 以投影去除_id, 令回傳形狀與select一致
|
|
356
|
+
let v = await collection.findOne({ id: pk }, { projection: { _id: 0 } })
|
|
357
|
+
|
|
358
|
+
//check, 判定基準與insert、save、del內對既有數據之認定一致
|
|
359
|
+
if (iseobj(v)) {
|
|
360
|
+
res = v
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
//不存在id, 回傳null
|
|
364
|
+
res = null
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
isErr = true
|
|
370
|
+
res = err
|
|
371
|
+
}
|
|
372
|
+
finally {
|
|
373
|
+
await client.close()
|
|
374
|
+
client = null
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (isErr) {
|
|
378
|
+
return Promise.reject(res)
|
|
379
|
+
}
|
|
380
|
+
return res
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* 插入數據,僅於id不存在時寫入,已存在者跳過且不覆寫
|
|
386
|
+
* 由MongoDB於唯一索引上原子完成[檢查id未存在]與[寫入],併發時同一id僅有一次成功
|
|
387
|
+
* 註: n為輸入筆數,nInserted為實際插入筆數,全數已存在而nInserted為0屬正常結果
|
|
388
|
+
*
|
|
389
|
+
* @memberOf WOrmMongodb
|
|
390
|
+
* @param {Object|Array} data 輸入數據物件或陣列
|
|
391
|
+
* @returns {Promise} 回傳Promise,resolve回傳插入結果,reject回傳錯誤訊息
|
|
392
|
+
*/
|
|
393
|
+
async function insert(data) {
|
|
394
|
+
let isErr = false
|
|
395
|
+
|
|
396
|
+
//check
|
|
397
|
+
if (!iseobj(data) && !isearr(data)) {
|
|
398
|
+
return {
|
|
399
|
+
n: 0,
|
|
400
|
+
nInserted: 0,
|
|
401
|
+
ok: 1,
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
//cloneDeep
|
|
406
|
+
data = cloneDeep(data)
|
|
407
|
+
|
|
408
|
+
//client
|
|
409
|
+
let client = new MongoClient(opt.url)
|
|
410
|
+
|
|
411
|
+
//res
|
|
412
|
+
let res = null
|
|
413
|
+
try {
|
|
414
|
+
|
|
415
|
+
//connect, 令連線失敗於寫入前即拋出, 屬影響全部數據之整批性錯誤
|
|
416
|
+
await client.connect()
|
|
417
|
+
|
|
418
|
+
//database, collection
|
|
419
|
+
let database = client.db(opt.db)
|
|
420
|
+
let collection = database.collection(opt.cl)
|
|
421
|
+
|
|
422
|
+
//check
|
|
423
|
+
if (!isarr(data)) {
|
|
424
|
+
data = [data]
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
//check id
|
|
428
|
+
data = map(data, function(v) {
|
|
429
|
+
if (!isestr(v.id)) {
|
|
430
|
+
v.id = genID()
|
|
431
|
+
}
|
|
432
|
+
return v
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
//ensureIndex
|
|
436
|
+
await ensureIndex(collection)
|
|
437
|
+
|
|
438
|
+
//nAll, n之基準為輸入筆數
|
|
439
|
+
let nAll = size(data)
|
|
440
|
+
|
|
441
|
+
//insertMany, ordered:false令已存在id者跳過而不中斷整批插入,
|
|
442
|
+
//同批含重複id時亦僅首筆成功, 故不須逐筆插入即可取得實際插入筆數
|
|
443
|
+
let nInserted = 0
|
|
444
|
+
try {
|
|
445
|
+
let r = await collection.insertMany(data, { ordered: false })
|
|
446
|
+
nInserted = r.insertedCount
|
|
447
|
+
}
|
|
448
|
+
catch (err) {
|
|
449
|
+
|
|
450
|
+
//僅重複鍵錯誤可視為[已存在id而跳過], 其餘錯誤影響全部數據, 須往外拋
|
|
451
|
+
if (!isDupKeyError(err)) {
|
|
452
|
+
throw err
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
//重複鍵錯誤時仍可由result取得實際插入筆數
|
|
456
|
+
nInserted = get(err, 'result.insertedCount', 0)
|
|
457
|
+
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
//res, 全數已存在而nInserted為0屬正常結果, 不視為錯誤
|
|
461
|
+
res = {
|
|
462
|
+
n: nAll,
|
|
463
|
+
nInserted,
|
|
464
|
+
ok: 1,
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
}
|
|
468
|
+
catch (err) {
|
|
469
|
+
isErr = true
|
|
470
|
+
res = err
|
|
471
|
+
}
|
|
472
|
+
finally {
|
|
473
|
+
await client.close()
|
|
474
|
+
client = null
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
//emit
|
|
478
|
+
if (!isErr) {
|
|
479
|
+
emitChange('insert', data, res)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (isErr) {
|
|
483
|
+
return Promise.reject(res)
|
|
484
|
+
}
|
|
485
|
+
return res
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* 儲存單筆數據,由MongoDB於單一updateOne內原子完成[查找id]與[更新或插入]
|
|
491
|
+
* 註: MongoDB單一文件操作本即為原子,故不須開啟transaction(transaction另須replica set,standalone不支援)
|
|
492
|
+
*
|
|
493
|
+
* @ignore
|
|
494
|
+
* @param {Object} collection 輸入資料表物件
|
|
495
|
+
* @param {Object} v 輸入數據物件
|
|
496
|
+
* @param {Boolean} autoInsert 輸入是否於查無數據時自動改以插入處理布林值
|
|
497
|
+
* @returns {Promise} 回傳Promise,resolve回傳本筆儲存結果,本筆失敗時亦resolve並以ok為0回報
|
|
498
|
+
*/
|
|
499
|
+
async function saveOne(collection, v, autoInsert) {
|
|
500
|
+
|
|
501
|
+
//nTry, 併發upsert可能因他方同時插入同一id而拋重複鍵錯誤,
|
|
502
|
+
//此時該id已存在, 重試即會走更新路徑, 故給予有限次數重試令其收斂
|
|
503
|
+
let nTry = 3
|
|
504
|
+
|
|
505
|
+
//rest
|
|
506
|
+
let rest = null
|
|
507
|
+
|
|
508
|
+
//inserted, 供結果定案後發出insert事件用
|
|
509
|
+
let inserted = false
|
|
510
|
+
|
|
511
|
+
for (let i = 0; i < nTry; i++) {
|
|
512
|
+
|
|
513
|
+
try {
|
|
514
|
+
|
|
515
|
+
//updateOne, upsert僅於autoInsert時開啟, 未開啟時查無數據即不寫入以免無中生有,
|
|
516
|
+
//由MongoDB於單一操作內原子完成[查找id]與[更新或插入],
|
|
517
|
+
//併發時不會有兩方各自讀到查無數據再各自插入而產生重複id, 亦不會有讀改寫之遺失更新
|
|
518
|
+
let r = await collection.updateOne({ id: v.id }, { $set: v }, {
|
|
519
|
+
upsert: autoInsert,
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
//matchedCount, modifiedCount, upsertedCount
|
|
523
|
+
let matchedCount = get(r, 'matchedCount', 0)
|
|
524
|
+
let modifiedCount = get(r, 'modifiedCount', 0)
|
|
525
|
+
let upsertedCount = get(r, 'upsertedCount', 0)
|
|
526
|
+
|
|
527
|
+
if (upsertedCount > 0) {
|
|
528
|
+
//原不存在而插入
|
|
529
|
+
|
|
530
|
+
//rest
|
|
531
|
+
rest = {
|
|
532
|
+
n: 1,
|
|
533
|
+
nInserted: 1,
|
|
534
|
+
nModified: 0,
|
|
535
|
+
ok: 1,
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
//inserted
|
|
539
|
+
inserted = true
|
|
540
|
+
|
|
541
|
+
}
|
|
542
|
+
else if (matchedCount > 0) {
|
|
543
|
+
//原已存在, 合併後內容有變更方為更新
|
|
544
|
+
//由MongoDB於伺服器端將待寫入物件合併進現值後與現值比對, 結果相同者不寫入而回modifiedCount為0,
|
|
545
|
+
//故僅給部份欄位且該些欄位值皆與現值相同時, 合併結果等於現值, nModified亦為0,
|
|
546
|
+
//係於同一原子操作內完成比對與寫入, 故不須另行預讀, 亦無預讀值過期之疑慮
|
|
547
|
+
|
|
548
|
+
//rest
|
|
549
|
+
rest = {
|
|
550
|
+
n: 1,
|
|
551
|
+
nInserted: 0,
|
|
552
|
+
nModified: modifiedCount > 0 ? 1 : 0,
|
|
553
|
+
ok: 1,
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
//查無數據且未開啟autoInsert
|
|
559
|
+
|
|
560
|
+
//rest
|
|
561
|
+
rest = {
|
|
562
|
+
n: 0,
|
|
563
|
+
nInserted: 0,
|
|
564
|
+
nModified: 0,
|
|
565
|
+
ok: 1,
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
break
|
|
571
|
+
}
|
|
572
|
+
catch (err) {
|
|
573
|
+
|
|
574
|
+
//重複鍵錯誤且未達重試上限則重試
|
|
575
|
+
if (isDupKeyError(err) && i < nTry - 1) {
|
|
576
|
+
continue
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
//其餘視為本筆失敗, 不中斷整批, 由呼叫端以ok與err判讀
|
|
580
|
+
|
|
581
|
+
//rest
|
|
582
|
+
rest = {
|
|
583
|
+
n: 1,
|
|
584
|
+
nInserted: 0,
|
|
585
|
+
nModified: 0,
|
|
586
|
+
ok: 0,
|
|
587
|
+
err: genErrMsg(err),
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
break
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
//emit, 須於結果定案後發出, 避免訂閱函數拋錯影響本筆結果
|
|
596
|
+
if (inserted) {
|
|
597
|
+
emitChange('insert', [v], rest)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return rest
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* 儲存數據,以id為準更新既有數據,未給之欄位會保留;id不存在且option.autoInsert為true時改為插入
|
|
606
|
+
* 註: n為id命中筆數,命中或經插入而產生皆為1;[內容相同]之判定基準為將待儲存物件合併進現值後結果與現值相同,
|
|
607
|
+
* 相同者不寫入而nModified為0;本筆失敗不中斷整批,該筆以ok為0並附err回報
|
|
608
|
+
*
|
|
609
|
+
* @memberOf WOrmMongodb
|
|
610
|
+
* @param {Object|Array} data 輸入數據物件或陣列
|
|
611
|
+
* @param {Object} [option={}] 輸入設定物件,預設為{}
|
|
612
|
+
* @param {boolean} [option.autoInsert=true] 輸入是否於儲存時發現原本無數據,則自動改以插入處理,預設為true
|
|
613
|
+
* @returns {Promise} 回傳Promise,resolve回傳與輸入等長之儲存結果陣列,reject回傳錯誤訊息
|
|
614
|
+
*/
|
|
615
|
+
async function save(data, option = {}) {
|
|
616
|
+
let isErr = false
|
|
617
|
+
|
|
618
|
+
//check
|
|
619
|
+
if (!iseobj(data) && !isearr(data)) {
|
|
620
|
+
return []
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
//cloneDeep
|
|
624
|
+
data = cloneDeep(data)
|
|
625
|
+
|
|
626
|
+
//autoInsert
|
|
627
|
+
let autoInsert = get(option, 'autoInsert', true)
|
|
628
|
+
|
|
629
|
+
//client
|
|
630
|
+
let client = new MongoClient(opt.url)
|
|
631
|
+
|
|
632
|
+
//res
|
|
633
|
+
let res = null
|
|
634
|
+
try {
|
|
635
|
+
|
|
636
|
+
//connect, 令連線失敗於寫入前即拋出, 屬影響全部數據之整批性錯誤
|
|
637
|
+
await client.connect()
|
|
638
|
+
|
|
639
|
+
//database, collection
|
|
640
|
+
let database = client.db(opt.db)
|
|
641
|
+
let collection = database.collection(opt.cl)
|
|
642
|
+
|
|
643
|
+
//check
|
|
644
|
+
if (!isarr(data)) {
|
|
645
|
+
data = [data]
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
//check id
|
|
649
|
+
data = map(data, function(v) {
|
|
650
|
+
if (!isestr(v.id)) {
|
|
651
|
+
v.id = genID()
|
|
652
|
+
}
|
|
653
|
+
return v
|
|
654
|
+
})
|
|
655
|
+
|
|
656
|
+
//ensureIndex
|
|
657
|
+
await ensureIndex(collection)
|
|
658
|
+
|
|
659
|
+
//pmSeries
|
|
660
|
+
res = await pmSeries(data, async(v) => {
|
|
661
|
+
return saveOne(collection, v, autoInsert)
|
|
662
|
+
})
|
|
663
|
+
|
|
664
|
+
}
|
|
665
|
+
catch (err) {
|
|
666
|
+
isErr = true
|
|
667
|
+
res = err
|
|
668
|
+
}
|
|
669
|
+
finally {
|
|
670
|
+
await client.close()
|
|
671
|
+
client = null
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
//emit
|
|
675
|
+
if (!isErr) {
|
|
676
|
+
emitChange('save', data, res)
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (isErr) {
|
|
680
|
+
return Promise.reject(res)
|
|
681
|
+
}
|
|
682
|
+
return res
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* 刪除數據
|
|
688
|
+
* 註: n為id命中筆數;未帶有效id者視為本筆無法處理,不送查詢條件且以ok為0並附err回報;
|
|
689
|
+
* 判斷本筆是否真的被刪除一律以nDeleted為準
|
|
690
|
+
*
|
|
691
|
+
* @memberOf WOrmMongodb
|
|
692
|
+
* @param {Object|Array} data 輸入數據物件或陣列
|
|
693
|
+
* @returns {Promise} 回傳Promise,resolve回傳與輸入等長之刪除結果陣列,reject回傳錯誤訊息
|
|
694
|
+
*/
|
|
695
|
+
async function del(data) {
|
|
696
|
+
let isErr = false
|
|
697
|
+
|
|
698
|
+
//check
|
|
699
|
+
if (!iseobj(data) && !isearr(data)) {
|
|
700
|
+
return []
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
//cloneDeep
|
|
704
|
+
data = cloneDeep(data)
|
|
705
|
+
|
|
706
|
+
//client
|
|
707
|
+
let client = new MongoClient(opt.url)
|
|
708
|
+
|
|
709
|
+
//res
|
|
710
|
+
let res = null
|
|
711
|
+
try {
|
|
712
|
+
|
|
713
|
+
//connect, 令連線失敗於刪除前即拋出, 屬影響全部數據之整批性錯誤
|
|
714
|
+
await client.connect()
|
|
715
|
+
|
|
716
|
+
//database, collection
|
|
717
|
+
let database = client.db(opt.db)
|
|
718
|
+
let collection = database.collection(opt.cl)
|
|
719
|
+
|
|
720
|
+
//check
|
|
721
|
+
if (!isarr(data)) {
|
|
722
|
+
data = [data]
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
//pmSeries
|
|
726
|
+
res = await pmSeries(data, async(v) => {
|
|
727
|
+
|
|
728
|
+
//id, del不補值, 未帶有效id者視為本筆無法處理
|
|
729
|
+
let id = get(v, 'id')
|
|
730
|
+
|
|
731
|
+
//check, 不得將無效id送進查詢條件, 因undefined經序列化為null會誤中id為null之數據
|
|
732
|
+
if (!isestr(id)) {
|
|
733
|
+
return {
|
|
734
|
+
n: 0,
|
|
735
|
+
nDeleted: 0,
|
|
736
|
+
ok: 0,
|
|
737
|
+
err: `invalid id[${id}]`,
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
//rest
|
|
742
|
+
let rest = null
|
|
743
|
+
|
|
744
|
+
try {
|
|
745
|
+
|
|
746
|
+
//deleteOne
|
|
747
|
+
let r = await collection.deleteOne({ id })
|
|
748
|
+
|
|
749
|
+
//nDeleted
|
|
750
|
+
let nDeleted = get(r, 'deletedCount', 0)
|
|
751
|
+
|
|
752
|
+
//rest, 未命中時nDeleted為0, 屬正常結果
|
|
753
|
+
rest = {
|
|
754
|
+
n: nDeleted,
|
|
755
|
+
nDeleted,
|
|
756
|
+
ok: 1,
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
}
|
|
760
|
+
catch (err) {
|
|
761
|
+
|
|
762
|
+
//本筆失敗不中斷整批
|
|
763
|
+
|
|
764
|
+
//rest
|
|
765
|
+
rest = {
|
|
766
|
+
n: 1,
|
|
767
|
+
nDeleted: 0,
|
|
768
|
+
ok: 0,
|
|
769
|
+
err: genErrMsg(err),
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return rest
|
|
775
|
+
})
|
|
776
|
+
|
|
777
|
+
}
|
|
778
|
+
catch (err) {
|
|
779
|
+
isErr = true
|
|
780
|
+
res = err
|
|
781
|
+
}
|
|
782
|
+
finally {
|
|
783
|
+
await client.close()
|
|
784
|
+
client = null
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
//emit
|
|
788
|
+
if (!isErr) {
|
|
789
|
+
emitChange('del', data, res)
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
if (isErr) {
|
|
793
|
+
return Promise.reject(res)
|
|
794
|
+
}
|
|
795
|
+
return res
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* 刪除全部數據,需與del分開,避免未傳數據導致直接刪除全表
|
|
801
|
+
* 註: n為實際刪除筆數,恆等於nDeleted;條件無命中時回傳0亦屬正常結果
|
|
802
|
+
*
|
|
803
|
+
* @memberOf WOrmMongodb
|
|
804
|
+
* @param {Object} [find={}] 輸入刪除條件物件
|
|
805
|
+
* @returns {Promise} 回傳Promise,resolve回傳刪除結果,reject回傳錯誤訊息
|
|
806
|
+
*/
|
|
807
|
+
async function delAll(find = {}) {
|
|
808
|
+
let isErr = false
|
|
809
|
+
|
|
810
|
+
//client
|
|
811
|
+
let client = new MongoClient(opt.url)
|
|
812
|
+
|
|
813
|
+
//res
|
|
814
|
+
let res = null
|
|
815
|
+
try {
|
|
816
|
+
|
|
817
|
+
//database, collection
|
|
818
|
+
let database = client.db(opt.db)
|
|
819
|
+
let collection = database.collection(opt.cl)
|
|
820
|
+
|
|
821
|
+
//deleteMany
|
|
822
|
+
let r = await collection.deleteMany(find)
|
|
823
|
+
|
|
824
|
+
//nDeleted
|
|
825
|
+
let nDeleted = get(r, 'deletedCount', 0)
|
|
826
|
+
|
|
827
|
+
//res
|
|
828
|
+
res = {
|
|
829
|
+
n: nDeleted,
|
|
830
|
+
nDeleted,
|
|
831
|
+
ok: 1,
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
}
|
|
835
|
+
catch (err) {
|
|
836
|
+
isErr = true
|
|
837
|
+
res = err
|
|
838
|
+
}
|
|
839
|
+
finally {
|
|
840
|
+
await client.close()
|
|
841
|
+
client = null
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
//emit
|
|
845
|
+
if (!isErr) {
|
|
846
|
+
emitChange('delAll', null, res)
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (isErr) {
|
|
850
|
+
return Promise.reject(res)
|
|
851
|
+
}
|
|
852
|
+
return res
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* 使用GridFS,插入數據,僅於id不存在時寫入,已存在者跳過且不覆寫
|
|
858
|
+
* 數據物件形狀為{ id, u8a },id未給時自動產生,u8a須為Uint8Array
|
|
859
|
+
* 註: n為輸入筆數,nInserted為實際插入筆數,全數已存在而nInserted為0屬正常結果
|
|
860
|
+
*
|
|
861
|
+
* @memberOf WOrmMongodb
|
|
862
|
+
* @param {Object|Array} data 輸入數據物件或陣列,各數據物件形狀為{ id, u8a }
|
|
863
|
+
* @returns {Promise} 回傳Promise,resolve回傳插入結果,reject回傳錯誤訊息
|
|
864
|
+
*/
|
|
865
|
+
async function insertGfs(data) {
|
|
866
|
+
let isErr = false
|
|
867
|
+
|
|
868
|
+
//check
|
|
869
|
+
if (!iseobj(data) && !isearr(data)) {
|
|
870
|
+
return {
|
|
871
|
+
n: 0,
|
|
872
|
+
nInserted: 0,
|
|
873
|
+
ok: 1,
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
//client
|
|
878
|
+
let client = new MongoClient(opt.url)
|
|
879
|
+
|
|
880
|
+
//res
|
|
881
|
+
let res = null
|
|
882
|
+
try {
|
|
883
|
+
|
|
884
|
+
//connect, 令連線失敗於寫入前即拋出, 屬影響全部數據之整批性錯誤
|
|
885
|
+
await client.connect()
|
|
886
|
+
|
|
887
|
+
//database
|
|
888
|
+
let database = client.db(opt.db)
|
|
889
|
+
|
|
890
|
+
//bucket
|
|
891
|
+
let bucket = new mongodb.GridFSBucket(database, {
|
|
892
|
+
chunkSizeBytes: 10 * 1024 * 1024, //10mb
|
|
893
|
+
bucketName: opt.cl
|
|
894
|
+
})
|
|
895
|
+
|
|
896
|
+
//clChunks
|
|
897
|
+
let clChunks = database.collection(`${opt.cl}.chunks`)
|
|
898
|
+
|
|
899
|
+
//check
|
|
900
|
+
if (!isarr(data)) {
|
|
901
|
+
data = [data]
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
//check id與u8a, 僅淺拷貝數據物件而不深拷貝u8a,
|
|
905
|
+
//因u8a僅供讀取, 深拷貝大量二進位數據成本過高;
|
|
906
|
+
//u8a無效屬呼叫端給值錯誤且整批函數無從逐筆回報, 故往外拋
|
|
907
|
+
data = map(data, function(v, k) {
|
|
908
|
+
v = { ...v }
|
|
909
|
+
if (!isestr(v.id)) {
|
|
910
|
+
v.id = genID()
|
|
911
|
+
}
|
|
912
|
+
if (!isu8arr(v.u8a)) {
|
|
913
|
+
throw new Error(`invalid data[${k}].u8a`)
|
|
914
|
+
}
|
|
915
|
+
return v
|
|
916
|
+
})
|
|
917
|
+
|
|
918
|
+
//ensureIndexGfs
|
|
919
|
+
await ensureIndexGfs(database)
|
|
920
|
+
|
|
921
|
+
//nAll, n之基準為輸入筆數
|
|
922
|
+
let nAll = size(data)
|
|
923
|
+
|
|
924
|
+
//上傳, 逐筆序列處理以免大量二進位數據同時佔用記憶體
|
|
925
|
+
let nInserted = 0
|
|
926
|
+
await pmSeries(data, async(v) => {
|
|
927
|
+
let inserted = await _uploadGfs(bucket, clChunks, v.id, v.u8a)
|
|
928
|
+
if (inserted) {
|
|
929
|
+
nInserted++
|
|
930
|
+
}
|
|
931
|
+
})
|
|
932
|
+
|
|
933
|
+
//res, 全數已存在而nInserted為0屬正常結果, 不視為錯誤
|
|
934
|
+
res = {
|
|
935
|
+
n: nAll,
|
|
936
|
+
nInserted,
|
|
937
|
+
ok: 1,
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
}
|
|
941
|
+
catch (err) {
|
|
942
|
+
isErr = true
|
|
943
|
+
res = err
|
|
944
|
+
}
|
|
945
|
+
finally {
|
|
946
|
+
await client.close()
|
|
947
|
+
client = null
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
//emit
|
|
951
|
+
if (!isErr) {
|
|
952
|
+
emitChange('insertGfs', data, res)
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (isErr) {
|
|
956
|
+
return Promise.reject(res)
|
|
957
|
+
}
|
|
958
|
+
return res
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* 使用GridFS,由主鍵查詢單筆數據
|
|
964
|
+
* 註: 查無數據或主鍵值無效時回傳null,判定基準與selectByPk一致
|
|
965
|
+
* 註: 本套件之主鍵欄位固定為id,尚未支援由呼叫端指定
|
|
966
|
+
* 本函數不得有副作用,故不建立唯一索引
|
|
967
|
+
*
|
|
968
|
+
* @memberOf WOrmMongodb
|
|
969
|
+
* @param {String} pk 輸入主鍵值字串,即數據之id
|
|
970
|
+
* @returns {Promise} 回傳Promise,resolve回傳數據物件{ id, u8a },若無此主鍵或主鍵值無效則回傳null,reject回傳錯誤訊息
|
|
971
|
+
*/
|
|
972
|
+
async function selectByPkGfs(pk) {
|
|
973
|
+
let isErr = false
|
|
974
|
+
|
|
975
|
+
//check
|
|
976
|
+
if (!isestr(pk)) {
|
|
977
|
+
//未給有效主鍵值視為查無數據, 判定基準與selectByPk一致
|
|
978
|
+
return null
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
//client
|
|
982
|
+
let client = new MongoClient(opt.url)
|
|
983
|
+
|
|
984
|
+
//core
|
|
985
|
+
let core = async (id) => {
|
|
986
|
+
|
|
987
|
+
//pm
|
|
988
|
+
let pm = genPm()
|
|
989
|
+
|
|
990
|
+
//database
|
|
991
|
+
let database = client.db(opt.db)
|
|
992
|
+
|
|
993
|
+
//bucket
|
|
994
|
+
let bucket = new mongodb.GridFSBucket(database, {
|
|
995
|
+
chunkSizeBytes: 10 * 1024 * 1024, //10mb
|
|
996
|
+
bucketName: opt.cl
|
|
997
|
+
})
|
|
998
|
+
|
|
999
|
+
//buf
|
|
1000
|
+
let buf = Buffer.from('')
|
|
1001
|
+
|
|
1002
|
+
//stream
|
|
1003
|
+
let sm = bucket.openDownloadStreamByName(id)
|
|
1004
|
+
sm.on('data', function (chunk) {
|
|
1005
|
+
buf = Buffer.concat([buf, chunk])
|
|
1006
|
+
})
|
|
1007
|
+
sm.on('error', function (err) {
|
|
1008
|
+
|
|
1009
|
+
//reject
|
|
1010
|
+
pm.reject(err)
|
|
1011
|
+
|
|
1012
|
+
})
|
|
1013
|
+
sm.on('end', function () {
|
|
1014
|
+
|
|
1015
|
+
//u8a
|
|
1016
|
+
let u8a = new Uint8Array(buf)
|
|
1017
|
+
|
|
1018
|
+
//clean memory
|
|
1019
|
+
buf = null
|
|
1020
|
+
|
|
1021
|
+
//resolve
|
|
1022
|
+
pm.resolve(u8a)
|
|
1023
|
+
|
|
1024
|
+
})
|
|
1025
|
+
|
|
1026
|
+
return pm
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
//res
|
|
1030
|
+
let res = null
|
|
1031
|
+
try {
|
|
1032
|
+
|
|
1033
|
+
//core
|
|
1034
|
+
let u8a = await core(pk)
|
|
1035
|
+
|
|
1036
|
+
//res, 形狀與insertGfs所收之數據物件一致
|
|
1037
|
+
res = {
|
|
1038
|
+
id: pk,
|
|
1039
|
+
u8a,
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
}
|
|
1043
|
+
catch (err) {
|
|
1044
|
+
|
|
1045
|
+
//check, GridFS查無檔案時驅動以code為ENOENT之錯誤回報, 屬正常結果故回傳null
|
|
1046
|
+
if (get(err, 'code') === 'ENOENT') {
|
|
1047
|
+
res = null
|
|
1048
|
+
}
|
|
1049
|
+
else {
|
|
1050
|
+
isErr = true
|
|
1051
|
+
res = err
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
}
|
|
1055
|
+
finally {
|
|
1056
|
+
await client.close()
|
|
1057
|
+
client = null
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (isErr) {
|
|
1061
|
+
return Promise.reject(res)
|
|
1062
|
+
}
|
|
1063
|
+
return res
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
async function _findGfs(find = {}, bucket) {
|
|
1068
|
+
let isErr = false
|
|
1069
|
+
|
|
1070
|
+
//res
|
|
1071
|
+
let res = null
|
|
1072
|
+
try {
|
|
1073
|
+
|
|
1074
|
+
//find
|
|
1075
|
+
let cursor = bucket.find(find)
|
|
1076
|
+
|
|
1077
|
+
//toArray
|
|
1078
|
+
res = await cursor.toArray()
|
|
1079
|
+
|
|
1080
|
+
}
|
|
1081
|
+
catch (err) {
|
|
1082
|
+
isErr = true
|
|
1083
|
+
res = err
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
if (isErr) {
|
|
1087
|
+
return Promise.reject(res)
|
|
1088
|
+
}
|
|
1089
|
+
return res
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* 使用GridFS,刪除數據
|
|
1095
|
+
* 註: n為id命中筆數;未帶有效id者視為本筆無法處理,以ok為0並附err回報;
|
|
1096
|
+
* 判斷本筆是否真的被刪除一律以nDeleted為準
|
|
1097
|
+
*
|
|
1098
|
+
* @memberOf WOrmMongodb
|
|
1099
|
+
* @param {Object|Array} data 輸入數據物件或陣列,各數據物件須帶id
|
|
1100
|
+
* @returns {Promise} 回傳Promise,resolve回傳與輸入等長之刪除結果陣列,reject回傳錯誤訊息
|
|
1101
|
+
*/
|
|
1102
|
+
async function delGfs(data) {
|
|
1103
|
+
let isErr = false
|
|
1104
|
+
|
|
1105
|
+
//check
|
|
1106
|
+
if (!iseobj(data) && !isearr(data)) {
|
|
1107
|
+
return []
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
//client
|
|
1111
|
+
let client = new MongoClient(opt.url)
|
|
1112
|
+
|
|
1113
|
+
//res
|
|
1114
|
+
let res = null
|
|
1115
|
+
try {
|
|
1116
|
+
|
|
1117
|
+
//connect, 令連線失敗於刪除前即拋出, 屬影響全部數據之整批性錯誤
|
|
1118
|
+
await client.connect()
|
|
1119
|
+
|
|
1120
|
+
//database
|
|
1121
|
+
let database = client.db(opt.db)
|
|
1122
|
+
|
|
1123
|
+
//bucket
|
|
1124
|
+
let bucket = new mongodb.GridFSBucket(database, {
|
|
1125
|
+
chunkSizeBytes: 10 * 1024 * 1024, //10mb
|
|
1126
|
+
bucketName: opt.cl
|
|
1127
|
+
})
|
|
1128
|
+
|
|
1129
|
+
//check
|
|
1130
|
+
if (!isarr(data)) {
|
|
1131
|
+
data = [data]
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
//pmSeries
|
|
1135
|
+
res = await pmSeries(data, async(v) => {
|
|
1136
|
+
|
|
1137
|
+
//id, delGfs不補值, 未帶有效id者視為本筆無法處理
|
|
1138
|
+
let id = get(v, 'id')
|
|
1139
|
+
|
|
1140
|
+
//check, 判定基準與del一致
|
|
1141
|
+
if (!isestr(id)) {
|
|
1142
|
+
return {
|
|
1143
|
+
n: 0,
|
|
1144
|
+
nDeleted: 0,
|
|
1145
|
+
ok: 0,
|
|
1146
|
+
err: `invalid id[${id}]`,
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
//rest
|
|
1151
|
+
let rest = null
|
|
1152
|
+
|
|
1153
|
+
try {
|
|
1154
|
+
|
|
1155
|
+
//_findGfs
|
|
1156
|
+
let ltdt = await _findGfs({ filename: id }, bucket)
|
|
1157
|
+
|
|
1158
|
+
//delete, 建立唯一索引後同一id至多一筆,
|
|
1159
|
+
//既有數據若尚存重複id則一併刪除並如實回報nDeleted
|
|
1160
|
+
let nDeleted = 0
|
|
1161
|
+
for (let vv of ltdt) {
|
|
1162
|
+
await bucket.delete(vv._id)
|
|
1163
|
+
nDeleted++
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
//rest, n為命中與否, 未命中時兩者皆為0且屬正常結果
|
|
1167
|
+
rest = {
|
|
1168
|
+
n: nDeleted > 0 ? 1 : 0,
|
|
1169
|
+
nDeleted,
|
|
1170
|
+
ok: 1,
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
}
|
|
1174
|
+
catch (err) {
|
|
1175
|
+
|
|
1176
|
+
//本筆失敗不中斷整批
|
|
1177
|
+
|
|
1178
|
+
//rest
|
|
1179
|
+
rest = {
|
|
1180
|
+
n: 1,
|
|
1181
|
+
nDeleted: 0,
|
|
1182
|
+
ok: 0,
|
|
1183
|
+
err: genErrMsg(err),
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
return rest
|
|
1189
|
+
})
|
|
1190
|
+
|
|
1191
|
+
}
|
|
1192
|
+
catch (err) {
|
|
1193
|
+
isErr = true
|
|
1194
|
+
res = err
|
|
1195
|
+
}
|
|
1196
|
+
finally {
|
|
1197
|
+
await client.close()
|
|
1198
|
+
client = null
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
//emit
|
|
1202
|
+
if (!isErr) {
|
|
1203
|
+
emitChange('delGfs', data, res)
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
if (isErr) {
|
|
1207
|
+
return Promise.reject(res)
|
|
1208
|
+
}
|
|
1209
|
+
return res
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
async function _delGfs(bid, bucket) {
|
|
1214
|
+
|
|
1215
|
+
//delete, 連同chunks一併刪除
|
|
1216
|
+
await bucket.delete(bid)
|
|
1217
|
+
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* 使用GridFS,刪除全部數據,需與delGfs分開,避免未傳數據導致直接刪除全部
|
|
1223
|
+
* 註: n為實際刪除筆數,恆等於nDeleted;條件無命中時回傳0亦屬正常結果
|
|
1224
|
+
* 本函數不建立唯一索引,以免既有數據尚存重複id時無法清除
|
|
1225
|
+
*
|
|
1226
|
+
* @memberOf WOrmMongodb
|
|
1227
|
+
* @param {Object} [find={}] 輸入刪除條件物件
|
|
1228
|
+
* @returns {Promise} 回傳Promise,resolve回傳刪除結果,reject回傳錯誤訊息
|
|
1229
|
+
*/
|
|
1230
|
+
async function delAllGfs(find = {}) {
|
|
1231
|
+
let isErr = false
|
|
1232
|
+
|
|
1233
|
+
//client
|
|
1234
|
+
let client = new MongoClient(opt.url)
|
|
1235
|
+
|
|
1236
|
+
//res
|
|
1237
|
+
let res = null
|
|
1238
|
+
try {
|
|
1239
|
+
|
|
1240
|
+
//database
|
|
1241
|
+
let database = client.db(opt.db)
|
|
1242
|
+
|
|
1243
|
+
//bucket
|
|
1244
|
+
let bucket = new mongodb.GridFSBucket(database, {
|
|
1245
|
+
chunkSizeBytes: 10 * 1024 * 1024, //10mb
|
|
1246
|
+
bucketName: opt.cl
|
|
1247
|
+
})
|
|
1248
|
+
|
|
1249
|
+
//_findGfs
|
|
1250
|
+
let ltdt = await _findGfs(find, bucket)
|
|
1251
|
+
|
|
1252
|
+
//ps
|
|
1253
|
+
let ps = map(ltdt, function(v) {
|
|
1254
|
+
let bid = v._id
|
|
1255
|
+
return _delGfs(bid, bucket)
|
|
1256
|
+
})
|
|
1257
|
+
|
|
1258
|
+
//all, 任一刪除失敗即往外拋, 屬整批性錯誤
|
|
1259
|
+
await Promise.all(ps)
|
|
1260
|
+
|
|
1261
|
+
//nDeleted, 全數刪除成功方會執行至此, 故實際刪除筆數即為符合條件筆數
|
|
1262
|
+
let nDeleted = size(ltdt)
|
|
1263
|
+
|
|
1264
|
+
//res
|
|
1265
|
+
res = {
|
|
1266
|
+
n: nDeleted,
|
|
1267
|
+
nDeleted,
|
|
1268
|
+
ok: 1,
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
}
|
|
1272
|
+
catch (err) {
|
|
1273
|
+
isErr = true
|
|
1274
|
+
res = err
|
|
1275
|
+
}
|
|
1276
|
+
finally {
|
|
1277
|
+
await client.close()
|
|
1278
|
+
client = null
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
//emit
|
|
1282
|
+
if (!isErr) {
|
|
1283
|
+
emitChange('delAllGfs', null, res)
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
if (isErr) {
|
|
1287
|
+
return Promise.reject(res)
|
|
1288
|
+
}
|
|
1289
|
+
return res
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
|
|
1293
|
+
//bind
|
|
1294
|
+
ee.select = select
|
|
1295
|
+
ee.selectByPk = selectByPk
|
|
1296
|
+
ee.insert = insert
|
|
1297
|
+
ee.save = save
|
|
1298
|
+
ee.del = del
|
|
1299
|
+
ee.delAll = delAll
|
|
1300
|
+
ee.selectByPkGfs = selectByPkGfs
|
|
1301
|
+
ee.insertGfs = insertGfs
|
|
1302
|
+
ee.delGfs = delGfs
|
|
1303
|
+
ee.delAllGfs = delAllGfs
|
|
1304
|
+
|
|
1305
|
+
|
|
1306
|
+
return ee
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
export default WOrmMongodb
|
|
875
1311
|
</code></pre>
|
|
876
1312
|
</article>
|
|
877
1313
|
</section>
|
|
@@ -886,7 +1322,7 @@ export default WOrmMongodb
|
|
|
886
1322
|
<br class="clear">
|
|
887
1323
|
|
|
888
1324
|
<footer>
|
|
889
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
1325
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Aug 16 2026 23:36:47 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
890
1326
|
</footer>
|
|
891
1327
|
|
|
892
1328
|
<script>prettyPrint();</script>
|