w-orm-mongodb 1.1.39 → 1.1.41

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.
@@ -45,8 +45,7 @@
45
45
 
46
46
  <section>
47
47
  <article>
48
- <pre class="prettyprint source linenums"><code>import events from 'events'
49
- import mongodb from 'mongodb'
48
+ <pre class="prettyprint source linenums"><code>import mongodb from 'mongodb'
50
49
  import stream from 'stream'
51
50
  import cloneDeep from 'lodash-es/cloneDeep.js'
52
51
  import every from 'lodash-es/every.js'
@@ -54,8 +53,10 @@ import get from 'lodash-es/get.js'
54
53
  import map from 'lodash-es/map.js'
55
54
  import omit from 'lodash-es/omit.js'
56
55
  import size from 'lodash-es/size.js'
56
+ import evem from 'wsemi/src/evem.mjs'
57
57
  import genPm from 'wsemi/src/genPm.mjs'
58
58
  import genID from 'wsemi/src/genID.mjs'
59
+ import isbol from 'wsemi/src/isbol.mjs'
59
60
  import isestr from 'wsemi/src/isestr.mjs'
60
61
  import isarr from 'wsemi/src/isarr.mjs'
61
62
  import isearr from 'wsemi/src/isearr.mjs'
@@ -67,14 +68,16 @@ import pmSeries from 'wsemi/src/pmSeries.mjs'
67
68
  /**
68
69
  * 操作資料庫(MongoDB)
69
70
  *
70
- * 本套件之主鍵欄位固定為id,尚未支援由呼叫端指定。
71
- * id為無業務語義之識別碼,故insert與save於輸入未帶有效id時自動補值;del不補值。
71
+ * 本套件之主鍵欄位固定為id,尚未支援由呼叫端指定。id為無業務語義之識別碼。
72
+ * opt.autoGenPk預設為true,insert、saveinsertGfs於輸入未帶有效id時自動產生;del於任一設定下皆不補值。
73
+ * opt.autoGenPk為false時套件一律不產生id,未帶有效id者以reject拋出,且id之唯一性與格式皆由呼叫端自負。
72
74
  *
73
75
  * @class
74
76
  * @param {Object} [opt={}] 輸入設定物件,預設{}
75
77
  * @param {String} [opt.url='mongodb://127.0.0.1:27017'] 輸入連接資料庫字串,預設'mongodb://127.0.0.1:27017'
76
78
  * @param {String} [opt.db='worm'] 輸入使用資料庫名稱字串,預設'worm'
77
79
  * @param {String} [opt.cl='test'] 輸入使用資料表名稱字串,預設'test'
80
+ * @param {Boolean} [opt.autoGenPk=true] 輸入是否於輸入未帶有效主鍵時自動產生主鍵值,預設true。為false時主鍵須由呼叫端自備,屬依賴注入之定位,主鍵之唯一性、格式與是否與既有資料衝突皆由呼叫端自負。本設定為建構層設定,不得於insert與save之option逐次覆寫
78
81
  * @returns {Object} 回傳操作資料庫物件,各事件功能詳見說明
79
82
  */
80
83
  function WOrmMongodb(opt = {}) {
@@ -92,6 +95,13 @@ function WOrmMongodb(opt = {}) {
92
95
  }
93
96
 
94
97
 
98
+ //autoGenPk, 預設開啟, 為false時主鍵一律由呼叫端自備, 套件不產生亦不補救
99
+ let autoGenPk = get(opt, 'autoGenPk')
100
+ if (!isbol(autoGenPk)) {
101
+ autoGenPk = true
102
+ }
103
+
104
+
95
105
  //_indexReady, 唯一索引只須建立一次, 以旗標記錄避免每次操作皆多一次round-trip
96
106
  let _indexReady = false
97
107
 
@@ -100,8 +110,9 @@ function WOrmMongodb(opt = {}) {
100
110
  let _indexGfsReady = false
101
111
 
102
112
 
103
- //ee
104
- let ee = new events.EventEmitter()
113
+ //ee, 採wsemi之evem(即eventemitter3), 其於'error'無監聽者時僅回傳false而不拋出,
114
+ //故本套件之操作行為不因呼叫端有無註冊監聽而改變; Node內建之EventEmitter具該拋出語義, 不可用
115
+ let ee = evem()
105
116
 
106
117
 
107
118
  //MongoClient
@@ -115,7 +126,7 @@ function WOrmMongodb(opt = {}) {
115
126
  * @param {Error|String} err 輸入錯誤物件或字串
116
127
  * @returns {String} 回傳錯誤訊息字串
117
128
  */
118
- function genErrMsg(err) {
129
+ function getErrMsg(err) {
119
130
 
120
131
  //message
121
132
  let message = get(err, 'message')
@@ -146,6 +157,59 @@ function WOrmMongodb(opt = {}) {
146
157
  }
147
158
 
148
159
 
160
+ /**
161
+ * 發出error事件,操作發生錯誤時發出,錯誤訊息一律轉為字串
162
+ * 註: 事件僅為附加通知,所送出之資訊必另有正規管道——整批性錯誤經Promise.reject,逐筆失敗經該筆之err欄位
163
+ * 註: 訂閱函數拋錯不得影響本次操作之結果,故另包try並自行吞掉
164
+ * 註: 正常結果不得發出本事件,如insert全數已存在、save合併後內容相同、del主鍵未命中、selectByPk查無數據
165
+ *
166
+ * @ignore
167
+ * @param {String} mode 輸入操作別字串
168
+ * @param {Array|null} data 輸入本次操作之數據
169
+ * @param {Error|String} err 輸入錯誤物件或字串
170
+ * @returns {undefined} 無回傳值
171
+ */
172
+ function emitError(mode, data, err) {
173
+ try {
174
+ ee.emit('error', mode, data, getErrMsg(err))
175
+ }
176
+ catch (errEmit) {
177
+ console.log(errEmit)
178
+ }
179
+ }
180
+
181
+
182
+ /**
183
+ * 檢查並補齊單筆數據之主鍵
184
+ * autoGenPk為true時未帶有效id者自動產生,為false時往外拋
185
+ * 註: 未帶有效id屬呼叫端未履行契約而非某一筆資料本身之問題,故為整批性錯誤而不降級為該筆ok為0,
186
+ * 若降級為逐筆結果,呼叫端易於整批resolve之下漏看,使[忘了給id]靜默變成[少寫了幾筆]
187
+ * 註: 本函數須於任何寫入之前一次對全部數據完成,令拋錯時同批之有效筆數亦不會被寫入
188
+ *
189
+ * @ignore
190
+ * @param {Object} v 輸入數據物件
191
+ * @param {Number} k 輸入數據於陣列內之索引
192
+ * @returns {Object} 回傳補齊主鍵之數據物件
193
+ */
194
+ function procPk(v, k) {
195
+
196
+ //check
197
+ if (!isestr(v.id)) {
198
+
199
+ //check, autoGenPk為false時主鍵須由呼叫端自備
200
+ if (!autoGenPk) {
201
+ throw new Error(`invalid data[${k}].id, autoGenPk is false`)
202
+ }
203
+
204
+ //genID
205
+ v.id = genID()
206
+
207
+ }
208
+
209
+ return v
210
+ }
211
+
212
+
149
213
  /**
150
214
  * 判定是否為唯一索引重複鍵錯誤(11000),批次插入時須全部寫入錯誤皆為重複鍵才算
151
215
  *
@@ -316,7 +380,12 @@ function WOrmMongodb(opt = {}) {
316
380
  client = null
317
381
  }
318
382
 
383
+ //check
319
384
  if (isErr) {
385
+
386
+ //emit, 整批性錯誤須於reject之前發出
387
+ emitError('select', null, res)
388
+
320
389
  return Promise.reject(res)
321
390
  }
322
391
  return res
@@ -374,7 +443,12 @@ function WOrmMongodb(opt = {}) {
374
443
  client = null
375
444
  }
376
445
 
446
+ //check
377
447
  if (isErr) {
448
+
449
+ //emit, 整批性錯誤須於reject之前發出
450
+ emitError('selectByPk', null, res)
451
+
378
452
  return Promise.reject(res)
379
453
  }
380
454
  return res
@@ -385,6 +459,7 @@ function WOrmMongodb(opt = {}) {
385
459
  * 插入數據,僅於id不存在時寫入,已存在者跳過且不覆寫
386
460
  * 由MongoDB於唯一索引上原子完成[檢查id未存在]與[寫入],併發時同一id僅有一次成功
387
461
  * 註: n為輸入筆數,nInserted為實際插入筆數,全數已存在而nInserted為0屬正常結果
462
+ * 註: opt.autoGenPk為true(預設)時未帶有效id者自動產生,為false時未帶有效id即reject且同批皆不寫入
388
463
  *
389
464
  * @memberOf WOrmMongodb
390
465
  * @param {Object|Array} data 輸入數據物件或陣列
@@ -424,13 +499,8 @@ function WOrmMongodb(opt = {}) {
424
499
  data = [data]
425
500
  }
426
501
 
427
- //check id
428
- data = map(data, function(v) {
429
- if (!isestr(v.id)) {
430
- v.id = genID()
431
- }
432
- return v
433
- })
502
+ //check id, 須於任何寫入之前一次完成, 令autoGenPk為false而拋錯時同批之有效筆數亦不會被寫入
503
+ data = map(data, procPk)
434
504
 
435
505
  //ensureIndex
436
506
  await ensureIndex(collection)
@@ -479,7 +549,12 @@ function WOrmMongodb(opt = {}) {
479
549
  emitChange('insert', data, res)
480
550
  }
481
551
 
552
+ //check
482
553
  if (isErr) {
554
+
555
+ //emit, 整批性錯誤須於reject之前發出
556
+ emitError('insert', data, res)
557
+
483
558
  return Promise.reject(res)
484
559
  }
485
560
  return res
@@ -584,7 +659,7 @@ function WOrmMongodb(opt = {}) {
584
659
  nInserted: 0,
585
660
  nModified: 0,
586
661
  ok: 0,
587
- err: genErrMsg(err),
662
+ err: getErrMsg(err),
588
663
  }
589
664
 
590
665
  break
@@ -597,6 +672,11 @@ function WOrmMongodb(opt = {}) {
597
672
  emitChange('insert', [v], rest)
598
673
  }
599
674
 
675
+ //emit, 逐筆失敗須於該筆結果定案後發出, 每筆一次
676
+ if (rest.ok === 0) {
677
+ emitError('save', [v], rest.err)
678
+ }
679
+
600
680
  return rest
601
681
  }
602
682
 
@@ -605,6 +685,7 @@ function WOrmMongodb(opt = {}) {
605
685
  * 儲存數據,以id為準更新既有數據,未給之欄位會保留;id不存在且option.autoInsert為true時改為插入
606
686
  * 註: n為id命中筆數,命中或經插入而產生皆為1;[內容相同]之判定基準為將待儲存物件合併進現值後結果與現值相同,
607
687
  * 相同者不寫入而nModified為0;本筆失敗不中斷整批,該筆以ok為0並附err回報
688
+ * 註: opt.autoGenPk為true(預設)時未帶有效id者自動產生,為false時未帶有效id即reject且同批皆不寫入
608
689
  *
609
690
  * @memberOf WOrmMongodb
610
691
  * @param {Object|Array} data 輸入數據物件或陣列
@@ -645,13 +726,8 @@ function WOrmMongodb(opt = {}) {
645
726
  data = [data]
646
727
  }
647
728
 
648
- //check id
649
- data = map(data, function(v) {
650
- if (!isestr(v.id)) {
651
- v.id = genID()
652
- }
653
- return v
654
- })
729
+ //check id, 須於任何寫入之前一次完成, 令autoGenPk為false而拋錯時同批之有效筆數亦不會被寫入
730
+ data = map(data, procPk)
655
731
 
656
732
  //ensureIndex
657
733
  await ensureIndex(collection)
@@ -676,7 +752,12 @@ function WOrmMongodb(opt = {}) {
676
752
  emitChange('save', data, res)
677
753
  }
678
754
 
755
+ //check
679
756
  if (isErr) {
757
+
758
+ //emit, 整批性錯誤須於reject之前發出
759
+ emitError('save', data, res)
760
+
680
761
  return Promise.reject(res)
681
762
  }
682
763
  return res
@@ -728,49 +809,60 @@ function WOrmMongodb(opt = {}) {
728
809
  //id, del不補值, 未帶有效id者視為本筆無法處理
729
810
  let id = get(v, 'id')
730
811
 
812
+ //rest
813
+ let rest = null
814
+
731
815
  //check, 不得將無效id送進查詢條件, 因undefined經序列化為null會誤中id為null之數據
732
816
  if (!isestr(id)) {
733
- return {
817
+
818
+ //rest
819
+ rest = {
734
820
  n: 0,
735
821
  nDeleted: 0,
736
822
  ok: 0,
737
823
  err: `invalid id[${id}]`,
738
824
  }
825
+
739
826
  }
827
+ else {
740
828
 
741
- //rest
742
- let rest = null
829
+ try {
743
830
 
744
- try {
831
+ //deleteOne
832
+ let r = await collection.deleteOne({ id })
745
833
 
746
- //deleteOne
747
- let r = await collection.deleteOne({ id })
834
+ //nDeleted
835
+ let nDeleted = get(r, 'deletedCount', 0)
748
836
 
749
- //nDeleted
750
- let nDeleted = get(r, 'deletedCount', 0)
837
+ //rest, 未命中時nDeleted為0, 屬正常結果
838
+ rest = {
839
+ n: nDeleted,
840
+ nDeleted,
841
+ ok: 1,
842
+ }
751
843
 
752
- //rest, 未命中時nDeleted為0, 屬正常結果
753
- rest = {
754
- n: nDeleted,
755
- nDeleted,
756
- ok: 1,
757
844
  }
845
+ catch (err) {
758
846
 
759
- }
760
- catch (err) {
847
+ //本筆失敗不中斷整批
761
848
 
762
- //本筆失敗不中斷整批
849
+ //rest
850
+ rest = {
851
+ n: 1,
852
+ nDeleted: 0,
853
+ ok: 0,
854
+ err: getErrMsg(err),
855
+ }
763
856
 
764
- //rest
765
- rest = {
766
- n: 1,
767
- nDeleted: 0,
768
- ok: 0,
769
- err: genErrMsg(err),
770
857
  }
771
858
 
772
859
  }
773
860
 
861
+ //emit, 逐筆失敗須於該筆結果定案後發出, 每筆一次
862
+ if (rest.ok === 0) {
863
+ emitError('del', [v], rest.err)
864
+ }
865
+
774
866
  return rest
775
867
  })
776
868
 
@@ -789,7 +881,12 @@ function WOrmMongodb(opt = {}) {
789
881
  emitChange('del', data, res)
790
882
  }
791
883
 
884
+ //check
792
885
  if (isErr) {
886
+
887
+ //emit, 整批性錯誤須於reject之前發出
888
+ emitError('del', data, res)
889
+
793
890
  return Promise.reject(res)
794
891
  }
795
892
  return res
@@ -846,7 +943,12 @@ function WOrmMongodb(opt = {}) {
846
943
  emitChange('delAll', null, res)
847
944
  }
848
945
 
946
+ //check
849
947
  if (isErr) {
948
+
949
+ //emit, 整批性錯誤須於reject之前發出
950
+ emitError('delAll', null, res)
951
+
850
952
  return Promise.reject(res)
851
953
  }
852
954
  return res
@@ -855,8 +957,9 @@ function WOrmMongodb(opt = {}) {
855
957
 
856
958
  /**
857
959
  * 使用GridFS,插入數據,僅於id不存在時寫入,已存在者跳過且不覆寫
858
- * 數據物件形狀為{ id, u8a },id未給時自動產生,u8a須為Uint8Array
960
+ * 數據物件形狀為{ id, u8a },u8a須為Uint8Array
859
961
  * 註: n為輸入筆數,nInserted為實際插入筆數,全數已存在而nInserted為0屬正常結果
962
+ * 註: opt.autoGenPk為true(預設)時未帶有效id者自動產生,為false時未帶有效id即reject且同批皆不寫入
860
963
  *
861
964
  * @memberOf WOrmMongodb
862
965
  * @param {Object|Array} data 輸入數據物件或陣列,各數據物件形狀為{ id, u8a }
@@ -906,9 +1009,7 @@ function WOrmMongodb(opt = {}) {
906
1009
  //u8a無效屬呼叫端給值錯誤且整批函數無從逐筆回報, 故往外拋
907
1010
  data = map(data, function(v, k) {
908
1011
  v = { ...v }
909
- if (!isestr(v.id)) {
910
- v.id = genID()
911
- }
1012
+ v = procPk(v, k)
912
1013
  if (!isu8arr(v.u8a)) {
913
1014
  throw new Error(`invalid data[${k}].u8a`)
914
1015
  }
@@ -952,7 +1053,12 @@ function WOrmMongodb(opt = {}) {
952
1053
  emitChange('insertGfs', data, res)
953
1054
  }
954
1055
 
1056
+ //check
955
1057
  if (isErr) {
1058
+
1059
+ //emit, 整批性錯誤須於reject之前發出
1060
+ emitError('insertGfs', data, res)
1061
+
956
1062
  return Promise.reject(res)
957
1063
  }
958
1064
  return res
@@ -1057,13 +1163,19 @@ function WOrmMongodb(opt = {}) {
1057
1163
  client = null
1058
1164
  }
1059
1165
 
1166
+ //check, 查無檔案已於catch內判定為正常結果而未設isErr, 故不會誤發error事件
1060
1167
  if (isErr) {
1168
+
1169
+ //emit, 整批性錯誤須於reject之前發出
1170
+ emitError('selectByPkGfs', null, res)
1171
+
1061
1172
  return Promise.reject(res)
1062
1173
  }
1063
1174
  return res
1064
1175
  }
1065
1176
 
1066
1177
 
1178
+ //_findGfs, 內部查找函數, 其reject由delGfs與delAllGfs之catch接住並於該處發出error事件, 故本函數不自行發出
1067
1179
  async function _findGfs(find = {}, bucket) {
1068
1180
  let isErr = false
1069
1181
 
@@ -1137,54 +1249,65 @@ function WOrmMongodb(opt = {}) {
1137
1249
  //id, delGfs不補值, 未帶有效id者視為本筆無法處理
1138
1250
  let id = get(v, 'id')
1139
1251
 
1252
+ //rest
1253
+ let rest = null
1254
+
1140
1255
  //check, 判定基準與del一致
1141
1256
  if (!isestr(id)) {
1142
- return {
1257
+
1258
+ //rest
1259
+ rest = {
1143
1260
  n: 0,
1144
1261
  nDeleted: 0,
1145
1262
  ok: 0,
1146
1263
  err: `invalid id[${id}]`,
1147
1264
  }
1265
+
1148
1266
  }
1267
+ else {
1149
1268
 
1150
- //rest
1151
- let rest = null
1269
+ try {
1152
1270
 
1153
- try {
1271
+ //_findGfs
1272
+ let ltdt = await _findGfs({ filename: id }, bucket)
1154
1273
 
1155
- //_findGfs
1156
- let ltdt = await _findGfs({ filename: id }, bucket)
1274
+ //delete, 建立唯一索引後同一id至多一筆,
1275
+ //既有數據若尚存重複id則一併刪除並如實回報nDeleted
1276
+ let nDeleted = 0
1277
+ for (let vv of ltdt) {
1278
+ await bucket.delete(vv._id)
1279
+ nDeleted++
1280
+ }
1157
1281
 
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
- }
1282
+ //rest, n為命中與否, 未命中時兩者皆為0且屬正常結果
1283
+ rest = {
1284
+ n: nDeleted > 0 ? 1 : 0,
1285
+ nDeleted,
1286
+ ok: 1,
1287
+ }
1165
1288
 
1166
- //rest, n為命中與否, 未命中時兩者皆為0且屬正常結果
1167
- rest = {
1168
- n: nDeleted > 0 ? 1 : 0,
1169
- nDeleted,
1170
- ok: 1,
1171
1289
  }
1290
+ catch (err) {
1172
1291
 
1173
- }
1174
- catch (err) {
1292
+ //本筆失敗不中斷整批
1175
1293
 
1176
- //本筆失敗不中斷整批
1294
+ //rest
1295
+ rest = {
1296
+ n: 1,
1297
+ nDeleted: 0,
1298
+ ok: 0,
1299
+ err: getErrMsg(err),
1300
+ }
1177
1301
 
1178
- //rest
1179
- rest = {
1180
- n: 1,
1181
- nDeleted: 0,
1182
- ok: 0,
1183
- err: genErrMsg(err),
1184
1302
  }
1185
1303
 
1186
1304
  }
1187
1305
 
1306
+ //emit, 逐筆失敗須於該筆結果定案後發出, 每筆一次
1307
+ if (rest.ok === 0) {
1308
+ emitError('delGfs', [v], rest.err)
1309
+ }
1310
+
1188
1311
  return rest
1189
1312
  })
1190
1313
 
@@ -1203,7 +1326,12 @@ function WOrmMongodb(opt = {}) {
1203
1326
  emitChange('delGfs', data, res)
1204
1327
  }
1205
1328
 
1329
+ //check
1206
1330
  if (isErr) {
1331
+
1332
+ //emit, 整批性錯誤須於reject之前發出
1333
+ emitError('delGfs', data, res)
1334
+
1207
1335
  return Promise.reject(res)
1208
1336
  }
1209
1337
  return res
@@ -1283,7 +1411,12 @@ function WOrmMongodb(opt = {}) {
1283
1411
  emitChange('delAllGfs', null, res)
1284
1412
  }
1285
1413
 
1414
+ //check
1286
1415
  if (isErr) {
1416
+
1417
+ //emit, 整批性錯誤須於reject之前發出
1418
+ emitError('delAllGfs', null, res)
1419
+
1287
1420
  return Promise.reject(res)
1288
1421
  }
1289
1422
  return res
@@ -1322,7 +1455,7 @@ export default WOrmMongodb
1322
1455
  <br class="clear">
1323
1456
 
1324
1457
  <footer>
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.
1458
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Aug 17 2026 08:49:55 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1326
1459
  </footer>
1327
1460
 
1328
1461
  <script>prettyPrint();</script>
package/docs/index.html CHANGED
@@ -71,7 +71,7 @@
71
71
  <br class="clear">
72
72
 
73
73
  <footer>
74
- 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.
74
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Aug 17 2026 08:49:55 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
75
75
  </footer>
76
76
 
77
77
  <script>prettyPrint();</script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "w-orm-mongodb",
3
- "version": "1.1.39",
3
+ "version": "1.1.41",
4
4
  "main": "dist/w-orm-mongodb.umd.js",
5
5
  "dependencies": {
6
6
  "mongodb": "^7.5.0",