@microi.net/cli 6.1.4 → 6.1.5

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.
Files changed (101) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.mcp.json +1 -1
  5. package/.workbuddy-plugin/marketplace.json +2 -2
  6. package/.workbuddy-plugin/plugin.json +1 -1
  7. package/assets/build-meta.json +3 -3
  8. package/cordis.patch.yml +1 -1
  9. package/package.json +1 -1
  10. package/scripts/codex-marketplace.json +20 -20
  11. package/scripts/mcp-codex-stdio-adapter.js +189 -189
  12. package/scripts/mcp-trae-windows-launcher.cmd +21 -21
  13. package/scripts/microi-cli-mcp.js +7 -7
  14. package/scripts/microi-skills.meta.json +288 -288
  15. package/skills/.microi-skills-version.json +2 -2
  16. package/skills/.progressive-disclosure-manifest.json +1 -1
  17. package/skills/ai-engine/references/ai-employees.md +48 -48
  18. package/skills/ai-engine/references/self-hosted-digital-human.md +59 -59
  19. package/skills/business-blueprint/SKILL.md +193 -193
  20. package/skills/datasource-engine/SKILL.md +93 -93
  21. package/skills/dos-orm/SKILL.md +105 -105
  22. package/skills/dos-orm/references/api-reference.md +229 -229
  23. package/skills/email-engine/SKILL.md +81 -81
  24. package/skills/email-engine/references/v8-email.md +34 -34
  25. package/skills/job-engine/SKILL.md +179 -179
  26. package/skills/message-notification/SKILL.md +160 -156
  27. package/skills/message-notification/references/contracts.md +119 -102
  28. package/skills/microi/SKILL.md +14 -14
  29. package/skills/microi-ai-application/SKILL.md +115 -115
  30. package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
  31. package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +10 -10
  32. package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +10 -10
  33. package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +10 -10
  34. package/skills/microi-codex/SKILL.md +130 -130
  35. package/skills/microi-datasource-mapping/SKILL.md +131 -131
  36. package/skills/microi-db-schema/SKILL.md +182 -182
  37. package/skills/microi-db-schema/references/core-tables.md +695 -695
  38. package/skills/microi-db-schema/references/form-component-options.md +256 -256
  39. package/skills/microi-db-schema/references/schema-overview.md +202 -202
  40. package/skills/microi-db-schema/references/schema.md +646 -646
  41. package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
  42. package/skills/microi-deployment/SKILL.md +262 -262
  43. package/skills/microi-deployment/references/deployment-matrix.md +112 -112
  44. package/skills/microi-docs-coverage/SKILL.md +133 -133
  45. package/skills/microi-docs-coverage/references/capability-map.md +91 -91
  46. package/skills/microi-form-engine/SKILL.md +338 -338
  47. package/skills/microi-form-engine/references/component-catalog.md +218 -218
  48. package/skills/microi-form-engine/references/data-source-events.md +124 -124
  49. package/skills/microi-left-right-layout/SKILL.md +141 -141
  50. package/skills/microi-microservice/references/runtime-delivery.md +282 -282
  51. package/skills/microi-solution-quotation/SKILL.md +79 -79
  52. package/skills/microi-sso/SKILL.md +102 -102
  53. package/skills/microi-sso/references/configuration-and-security.md +53 -53
  54. package/skills/microi-sso/references/inbound.md +53 -53
  55. package/skills/microi-sso/references/outbound.md +43 -43
  56. package/skills/microi-system-delivery/references/context-quality.md +3 -3
  57. package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +11 -11
  58. package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +12 -12
  59. package/skills/microi-system-delivery/references/progressive-03-/345/256/211/345/205/250/344/270/216/350/267/250/347/253/257/351/252/214/346/224/266.md +8 -8
  60. package/skills/module-engine/SKILL.md +297 -297
  61. package/skills/module-engine/references/module-config.md +204 -204
  62. package/skills/ocr-engine/SKILL.md +113 -113
  63. package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +10 -10
  64. package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +12 -12
  65. package/skills/performance-testing/SKILL.md +227 -227
  66. package/skills/print-engine/SKILL.md +259 -259
  67. package/skills/production-readonly-audit/SKILL.md +41 -41
  68. package/skills/report-engine/SKILL.md +83 -83
  69. package/skills/search-engine/SKILL.md +75 -75
  70. package/skills/spider-engine/SKILL.md +190 -190
  71. package/skills/system-observability/SKILL.md +264 -264
  72. package/skills/system-observability/references/memory-incident-triage.md +77 -77
  73. package/skills/translate-engine/SKILL.md +140 -140
  74. package/skills/ui-design/assets/templates/MCI-DESIGN.md +206 -206
  75. package/skills/ui-design/references/design-pattern-library.md +184 -184
  76. package/skills/ui-design/references/mci-design-contract.md +163 -163
  77. package/skills/ui-design/references/motion-and-media.md +78 -78
  78. package/skills/ui-design/references/product-flow-recipes.md +94 -94
  79. package/skills/uniapp-mall-assets/SKILL.md +176 -176
  80. package/skills/unity-integration/SKILL.md +178 -178
  81. package/skills/unity-integration/references/sdk-api.md +82 -82
  82. package/skills/unity-integration/references/toolbox-migration.md +66 -66
  83. package/skills/unity-integration/references/webgl-hosting.md +57 -57
  84. package/skills/v8-cache-pattern/SKILL.md +320 -320
  85. package/skills/v8-debugging/SKILL.md +284 -284
  86. package/skills/v8-explorer-tree/SKILL.md +228 -228
  87. package/skills/v8-file-upload/references/cdn-alias-repair.md +13 -13
  88. package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
  89. package/skills/v8-frontend-events/references/bluetooth-print.md +258 -258
  90. package/skills/v8-image-processing/SKILL.md +190 -190
  91. package/skills/v8-image-processing/references/api-reference.md +623 -623
  92. package/skills/v8-mongodb/SKILL.md +257 -241
  93. package/skills/v8-mq-mqtt/references/mqtt-production.md +352 -352
  94. package/skills/v8-sql-query/SKILL.md +302 -302
  95. package/skills/v8-template-engine/SKILL.md +167 -167
  96. package/skills/v8-utilities/references/platform-http-routes.md +83 -83
  97. package/skills/v8-workflow/references/workflow-configuration.md +49 -49
  98. package/skills/vision-engine/SKILL.md +160 -160
  99. package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
  100. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +34 -34
  101. package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +6 -6
@@ -1,241 +1,257 @@
1
- ---
2
- name: v8-mongodb
3
- description: Microi V8 MongoDB 指南。用于使用 V8.MongoDb 文档读写、GetPartitionedTableData 跨年跨月游标分页、对象过滤和原生 ObjectId。
4
- ---
5
-
6
- > **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
7
-
8
- # Microi V8 MongoDB 操作
9
-
10
- 你正在开发 Microi 吾码平台的 V8 引擎代码,需要使用 MongoDB 存储非结构化数据(如日志、IoT 数据、大文档等)。
11
-
12
- ## V8.MongoDb API
13
-
14
- ### 存量 MongoDB 兼容诊断
15
-
16
- - `reports wire version 6 ... requires at least 9` 是驱动与服务端不兼容,不是日志为空,也不是 Token 失效。先记录原始错误和服务端真实协议,不能把 wire version 6 推断成 MongoDB 4.2。
17
- - 平台兼容镜像以含安全修复的驱动 3.11.2 构建,恢复平台 CRUD/日志所需的 MongoDB 3.6 协议路径;不是降级至 2.30,也不声明上游继续维护 3.6。来源、单文件补丁和摘要维护在 `Microi.Server/Microi.MongoDB.Driver/`。
18
- - 普通开发与全部默认测试先从当前 MCP 同源只读诊断发现真实 MongoDB 版本,沿已授权隔离范围执行认证、BSON、读写、索引、幂等重放、游标和租户隔离断言;不为旧版或其它版本重复询问、建库或新增服务。配置标签和 wire version 不能冒充实际版本回读。
19
- - 只有任务明确修改或验证存量兼容层、旧版本缺陷或跨版本升级时,才按该兼容目标扩展真实矩阵(例如需支持的 3.6 协议端与当前 MCP 实际版本),不固定假设当前端是 7.x。每个版本必须独立回读和实际执行,未执行记未覆盖;不得只验证编译或 ping,也不得把驱动兼容当作修复旧数据库服务端自身漏洞。
20
- - C# 驱动改动需要更新后端镜像才生效。镜像更新后通过 `microi_query_system_observability` 回读日志、队列持久化和错误状态;查询失败应原样报错,禁止返回成功空表。
21
-
22
- | 方法 | 说明 |
23
- |------|------|
24
- | `V8.MongoDb.AddFormData({...})` | 新增文档 |
25
- | `V8.MongoDb.UptFormData({...})` | 修改文档(按 Id) |
26
- | `V8.MongoDb.UptFormDataByWhere({...})` | 按非空 `_Where` 批量修改,禁止修改 `_id` |
27
- | `V8.MongoDb.DelFormData({...})` | 删除文档(按 Id) |
28
- | `V8.MongoDb.DelFormDataByWhere({...})` | 按非空 `_Where` 批量删除 |
29
- | `V8.MongoDb.GetFormData({...})` | 查询单个文档(按 Id) |
30
- | `V8.MongoDb.GetTableData({...})` | 查询文档列表 |
31
- | `V8.MongoDb.GetPartitionedTableData({...})` | 当前租户年度库、月度集合及旧年度集合的有界游标分页 |
32
- | `V8.MongoDb.NewId()` | 生成 MongoDB Id |
33
-
34
- ## 新增文档
35
-
36
- ```javascript
37
- var newId = V8.MongoDb.NewId();
38
- V8.MongoDb.AddFormData({
39
- DbName: 'sys_log_2024', // 数据库名
40
- TableName: 'log_2024_12', // 集合(表)名
41
- Id: newId, // 可选,不指定自动生成
42
- _FormData: {
43
- UserId: V8.CurrentUser.Id,
44
- Action: '登录',
45
- IP: '192.168.1.1',
46
- CreateTime: DateNow('yyyy-MM-dd HH:mm:ss')
47
- }
48
- });
49
- ```
50
-
51
- ## 修改文档
52
-
53
- ```javascript
54
- V8.MongoDb.UptFormData({
55
- DbName: 'sys_log_2024',
56
- TableName: 'log_2024_12',
57
- Id: V8.Param.id, // 必传
58
- _FormData: {
59
- Action: '更新操作',
60
- UpdateTime: DateNow('yyyy-MM-dd HH:mm:ss')
61
- }
62
- });
63
- ```
64
-
65
- ### 按条件批量修改
66
-
67
- ```javascript
68
- var result = V8.MongoDb.UptFormDataByWhere({
69
- DbName: 'diy_chat_' + V8.OsClient.toLowerCase(),
70
- TableName: 'chat_' + DateNow('yyyy'),
71
- _Where: [
72
- ['FromUserId', '=', V8.Param.PeerUserId],
73
- ['ToUserId', '=', V8.CurrentUser.Id],
74
- ['IsRead', '=', false]
75
- ],
76
- _FormData: { IsRead: true }
77
- });
78
- ```
79
-
80
- `_Where` 缺失、为空或包含无效条件时必须返回失败,不得执行全集合更新。`_FormData` 禁止设置 `_id` 或 `_id.*`。返回值的 `Data` 包含 `MatchedCount` 和 `ModifiedCount`。
81
-
82
- ## 删除文档
83
-
84
- ```javascript
85
- V8.MongoDb.DelFormData({
86
- DbName: 'sys_log_2024',
87
- TableName: 'log_2024_12',
88
- Id: V8.Param.id // 必传
89
- });
90
- ```
91
-
92
- ### 按条件批量删除
93
-
94
- ```javascript
95
- var result = V8.MongoDb.DelFormDataByWhere({
96
- DbName: 'diy_chat_' + V8.OsClient.toLowerCase(),
97
- TableName: 'chat_last_contact',
98
- _Where: [
99
- ['UserId', '=', V8.CurrentUser.Id],
100
- ['ContactUserId', '=', V8.Param.PeerUserId]
101
- ]
102
- });
103
- ```
104
-
105
- 删除条件必须包含当前权威用户/资源边界,不能只用可伪造的前端参数。返回值的 `Data` 包含 `DeletedCount`。
106
-
107
- ## 查询单个文档
108
-
109
- ```javascript
110
- var result = V8.MongoDb.GetFormData({
111
- DbName: 'sys_log_2024',
112
- TableName: 'log_2024_12',
113
- Id: V8.Param.id // 必传
114
- });
115
- ```
116
-
117
- ## 查询文档列表
118
-
119
- ```javascript
120
- var result = V8.MongoDb.GetTableData({
121
- DbName: 'sys_log_2024',
122
- TableName: 'log_2024_12',
123
- _Where: [
124
- ['Type', '=', '访问菜单'],
125
- ['OR', 'Type', '=', '点击V8按钮']
126
- ],
127
- _OrderBy: 'CreateTime',
128
- _OrderByType: 'DESC',
129
- _PageIndex: 1,
130
- _PageSize: 20
131
- });
132
- ```
133
-
134
- `GetFormData` 和 `GetTableData` 属于 dynamic 无模式读取。服务端会在 MongoDB 投影阶段过滤 BSON 内部 `_t` CLR 类型判别字段,避免存量强类型 C# 写入留下的旧类型名称触发反序列化失败。`_t` 不是 V8 业务契约;业务需要类型标记时应使用自有字段(例如 `DocumentType`),不得读取、筛选或依赖 `_t`。强类型 C# MongoDB 模型仍按自身的多态映射处理。
135
-
136
- ### 原生 `_id` 过滤
137
-
138
- `_Where: [['_id', 'In', ids]]` 支持原生 ObjectId 的数组或逗号分隔字符串,每次 1–1000 项。`=`、`!=`、范围比较与 `NotIn` 同样使用原生 ObjectId;每项必须是合法的 24 位十六进制标识。无效值返回失败,不能忽略条件后退化成全表查询。普通业务字符串 Id 应使用自有字段,不要伪装成原生 `_id`。
139
-
140
- ## 跨年跨月游标分页
141
-
142
- 海量聊天/日志不要只查当前月份,不要逐月 `Count + Skip` 或一次加载全历史。使用 `GetPartitionedTableData` 存储原子,接口引擎继续负责 DiyToken、成员资格、消息双方、业务权限与公开 DTO。平台 SignalR 聊天必须继续调用应用商城拥有的 `platform-chat-runtime`,不能另写业务 Controller。
143
-
144
- ```javascript
145
- // 必须先完成业务权限校验;身份来自当前 V8 上下文,前缀来自可信代码。
146
- var result = V8.MongoDb.GetPartitionedTableData({
147
- DatabasePrefix: 'audit_log', TablePrefix: 'event',
148
- _Where: [['UserId', '=', V8.CurrentUser.Id]],
149
- IndexFields: ['UserId'],
150
- PageSize: 30, MaxPartitions: 64,
151
- Cursor: V8.Param.Cursor || ''
152
- });
153
- if (result.Code !== 1) return result;
154
- // result.Data: { Rows, HasMore, NextCursor, ScannedPartitions }
155
- // 对外返回前显式选择业务字段,不能透传内部 _PartitionDb / _PartitionTable。
156
- return { Code: 1, Data: {
157
- Rows: result.Data.Rows.map(function(row) {
158
- return { Id: row._id, CreateTime: row.CreateTime, Action: row.Action };
159
- }),
160
- HasMore: result.Data.HasMore, NextCursor: result.Data.NextCursor
161
- }};
162
- ```
163
-
164
- - 命名:只发现当前租户的 `{DatabasePrefix}_{tenant小写}_{yyyy}` 和兼容旧库 `{DatabasePrefix}_{tenant小写}`;集合为 `{TablePrefix}_{yyyyMM}`、`{TablePrefix}_{yyyy_MM}` 或旧 `{TablePrefix}_{yyyy}`。年度库与集合年份必须一致。不能传任意库/集合列表,不能用普通用户输入控制前缀或索引。
165
- - `PageSize` 默认 30,范围 1–100(不是 `_PageSize`);`MaxPartitions` 默认 64,范围 1–128。目录最多 200 个租户库、2400 个有效集合。总调用限时 20 秒,单个集合查询限时 10 秒;超限/存储故障返回失败,不能冒充历史结束。
166
- - `_Where` 必须非空且有效;双向聊天可用 `_WhereAny` 传 1–4 组非空条件,组内 AND、组间 OR。指定 `_WhereAny` 时不再合并 `_Where`,每个分支都必须独立包含权威身份/资源边界。
167
- - `IndexFields` 可选,最多 3 个互异安全字段;按这些字段升序加 `CreateTime DESC, _id DESC` 创建复合索引。文档必须使用 BSON 日期 `CreateTime` 和原生 ObjectId `_id`。稳定排序按两者倒序,页内旧/新分区重复 `_id` 合并;普通页不执行 Count。
168
- - `Cursor` 是服务端返回、绑定租户/前缀/过滤条件的 opaque 字符串,最大 2048 字符。它是翻页位置而非鉴权凭据,禁止客户端解析或替换为页码。查询条件改变必须清空游标。即使 `Rows=[]`,只要 `HasMore=true` 仍需用新的 `NextCursor` 继续;跨空月、跨年和旧年度表不能提前截止。
169
- - `CountOnly:true` 返回 `{ Count }`,仍执行权限条件,扫描范围超过 `MaxPartitions` 直接失败而不返回部分总数。它计数物理行,迁移时不要复制未读事实到多个分区;需要业务去重计数时由权威索引另行维护。
170
- - 新消息按原始发生时间选择年度库/月度集合。`AddFormData` 的可选顶层 `OccurredAt` 用于可信后端重放保持 `CreateTime`,不得直接信任客户端时间;默认仍使用服务端当前时间。跨月重试必须用稳定业务 Id 和持久分区定位复用原始事实,不能在新月份再写一条。
171
- - 前端采用滚动异步加载、稳定 Id 合并、请求代际隔离和向前插入锚点补偿。实时消息只增量合并;已读回执读取有界最新页,不能重置旧历史游标或把未展示的全历史标为已读。
172
-
173
- 该原子需部署相应 Core/MongoDB/API 组件并更新 Managed 应用运行时。源码测试不等于线上 MongoDB、SignalR 或浏览器验收;至少覆盖跨月、跨年、空月、同时间多消息、旧年度集合、重复迁移数据、跨租户拒绝、断线重试和滚动位置。
174
-
175
- ## 实战模式
176
-
177
- ### IoT 设备日志存储
178
-
179
- ```javascript
180
- // 接收 MQTT 消息后存入 MongoDB
181
- var eventName = V8.EventName;
182
- if (eventName === 'MessageReceived') {
183
- V8.MongoDb.AddFormData({
184
- DbName: 'iot_data',
185
- TableName: 'device_log_' + DateNow('yyyy_MM'),
186
- _FormData: {
187
- DeviceId: V8.MQTT.ClientId,
188
- Topic: V8.MQTT.Topic,
189
- Payload: V8.MQTT.Payload,
190
- Timestamp: DateNow('yyyy-MM-dd HH:mm:ss')
191
- }
192
- });
193
- }
194
- ```
195
-
196
- ### 操作审计日志
197
-
198
- ```javascript
199
- // 在 SubmitAfterServerV8.js 中记录审计日志到 MongoDB
200
- V8.MongoDb.AddFormData({
201
- DbName: 'audit_log',
202
- TableName: 'form_audit_' + DateNow('yyyy'),
203
- _FormData: {
204
- TableName: V8.TableModel.Name,
205
- Action: V8.FormSubmitAction,
206
- DataId: V8.Form.Id,
207
- UserId: V8.CurrentUser.Id,
208
- UserName: V8.CurrentUser.Name,
209
- OldData: V8.FormSubmitAction === 'Update' ? JSON.stringify(V8.OldForm) : null,
210
- NewData: JSON.stringify(V8.Form),
211
- CreateTime: DateNow('yyyy-MM-dd HH:mm:ss')
212
- }
213
- });
214
- ```
215
-
216
- ### 按月分表查询
217
-
218
- ```javascript
219
- // 查询指定月份的日志
220
- var month = V8.Param.month || DateNow('yyyy_MM');
221
- var result = V8.MongoDb.GetTableData({
222
- DbName: 'sys_log_2024',
223
- TableName: 'log_' + month,
224
- _Where: [
225
- ['UserId', '=', V8.CurrentUser.Id]
226
- ]
227
- });
228
-
229
- return { Code: 1, Data: result };
230
- ```
231
-
232
- ## 注意事项
233
-
234
- - MongoDB 参数统一使用**对象格式**:`{ DbName, TableName, Id, _FormData, _Where, _OrderBy, _OrderByType }`
235
- - `DbName` 是 MongoDB 数据库名,`TableName` 是集合名
236
- - `_Where` 条件语法与 `V8.FormEngine` 一致
237
- - 批量写入仅接受安全字段名、已知操作符和非空条件;条件中的租户、用户和资源 Id 应来自 `V8.OsClient` / `V8.CurrentUser` / 权威回查,不得信任 `V8.Param` 中的同名身份字段
238
- - 非主库 V8 运行时会把 MongoDB 操作绑定到当前租户;显式传入其它 `OsClient` 不能跨租户
239
- - 适合存储日志、IoT 数据、大文档等非结构化 / 海量数据
240
- - 建议按时间分库分表(如 `log_2024_01`),便于清理历史数据
241
- - MongoDB 操作不参与 `V8.DbTrans` 事务。批量写入 `Code=1` 后即是已提交事实;后续 Hook/投递失败应返回警告或进入补偿,不得返回“未发生”导致盲目重试,重试必须有稳定业务 Id 幂等
1
+ ---
2
+ name: v8-mongodb
3
+ description: Microi V8 MongoDB 指南。用于使用 V8.MongoDb 文档读写、GetPartitionedTableData 跨年跨月游标分页、对象过滤和原生 ObjectId。
4
+ ---
5
+
6
+ > **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
7
+
8
+ # Microi V8 MongoDB 操作
9
+
10
+ 你正在开发 Microi 吾码平台的 V8 引擎代码,需要使用 MongoDB 存储非结构化数据(如日志、IoT 数据、大文档等)。
11
+
12
+ ## V8.MongoDb API
13
+
14
+ ### 存量 MongoDB 兼容诊断
15
+
16
+ - `reports wire version 6 ... requires at least 9` 是驱动与服务端不兼容,不是日志为空,也不是 Token 失效。先记录原始错误和服务端真实协议,不能把 wire version 6 推断成 MongoDB 4.2。
17
+ - 平台兼容镜像以含安全修复的驱动 3.11.2 构建,恢复平台 CRUD/日志所需的 MongoDB 3.6 协议路径;不是降级至 2.30,也不声明上游继续维护 3.6。来源、单文件补丁和摘要维护在 `Microi.Server/Microi.MongoDB.Driver/`。
18
+ - 普通开发与全部默认测试先从当前 MCP 同源只读诊断发现真实 MongoDB 版本,沿已授权隔离范围执行认证、BSON、读写、索引、幂等重放、游标和租户隔离断言;不为旧版或其它版本重复询问、建库或新增服务。配置标签和 wire version 不能冒充实际版本回读。
19
+ - 只有任务明确修改或验证存量兼容层、旧版本缺陷或跨版本升级时,才按该兼容目标扩展真实矩阵(例如需支持的 3.6 协议端与当前 MCP 实际版本),不固定假设当前端是 7.x。每个版本必须独立回读和实际执行,未执行记未覆盖;不得只验证编译或 ping,也不得把驱动兼容当作修复旧数据库服务端自身漏洞。
20
+ - C# 驱动改动需要更新后端镜像才生效。镜像更新后通过 `microi_query_system_observability` 回读日志、队列持久化和错误状态;查询失败应原样报错,禁止返回成功空表。
21
+
22
+ | 方法 | 说明 |
23
+ |------|------|
24
+ | `V8.MongoDb.AddFormData({...})` | 新增文档 |
25
+ | `V8.MongoDb.UptFormData({...})` | 修改文档(按 Id) |
26
+ | `V8.MongoDb.UptFormDataByWhere({...})` | 按非空 `_Where` 批量修改,禁止修改 `_id` |
27
+ | `V8.MongoDb.DelFormData({...})` | 删除文档(按 Id) |
28
+ | `V8.MongoDb.DelFormDataByWhere({...})` | 按非空 `_Where` 批量删除 |
29
+ | `V8.MongoDb.GetFormData({...})` | 查询单个文档(按 Id) |
30
+ | `V8.MongoDb.GetTableData({...})` | 查询文档列表 |
31
+ | `V8.MongoDb.GetPartitionedTableData({...})` | 当前租户年度库、月度集合及旧年度集合的有界游标分页 |
32
+ | `V8.MongoDb.NewId()` | 生成 MongoDB Id |
33
+
34
+ ## 新增文档
35
+
36
+ ```javascript
37
+ var newId = V8.MongoDb.NewId();
38
+ V8.MongoDb.AddFormData({
39
+ DbName: 'sys_log_2024', // 数据库名
40
+ TableName: 'log_2024_12', // 集合(表)名
41
+ Id: newId, // 可选,不指定自动生成
42
+ _FormData: {
43
+ UserId: V8.CurrentUser.Id,
44
+ Action: '登录',
45
+ IP: '192.168.1.1',
46
+ CreateTime: DateNow('yyyy-MM-dd HH:mm:ss')
47
+ }
48
+ });
49
+ ```
50
+
51
+ ## 修改文档
52
+
53
+ ```javascript
54
+ V8.MongoDb.UptFormData({
55
+ DbName: 'sys_log_2024',
56
+ TableName: 'log_2024_12',
57
+ Id: V8.Param.id, // 必传
58
+ _FormData: {
59
+ Action: '更新操作',
60
+ UpdateTime: DateNow('yyyy-MM-dd HH:mm:ss')
61
+ }
62
+ });
63
+ ```
64
+
65
+ ### 按条件批量修改
66
+
67
+ ```javascript
68
+ var result = V8.MongoDb.UptFormDataByWhere({
69
+ DbName: 'diy_chat_' + V8.OsClient.toLowerCase(),
70
+ TableName: 'chat_' + DateNow('yyyy'),
71
+ _Where: [
72
+ ['FromUserId', '=', V8.Param.PeerUserId],
73
+ ['ToUserId', '=', V8.CurrentUser.Id],
74
+ ['IsRead', '=', false]
75
+ ],
76
+ _FormData: { IsRead: true }
77
+ });
78
+ ```
79
+
80
+ `_Where` 缺失、为空或包含无效条件时必须返回失败,不得执行全集合更新。`_FormData` 禁止设置 `_id` 或 `_id.*`。返回值的 `Data` 包含 `MatchedCount` 和 `ModifiedCount`。
81
+
82
+ ## 删除文档
83
+
84
+ ```javascript
85
+ V8.MongoDb.DelFormData({
86
+ DbName: 'sys_log_2024',
87
+ TableName: 'log_2024_12',
88
+ Id: V8.Param.id // 必传
89
+ });
90
+ ```
91
+
92
+ ### 按条件批量删除
93
+
94
+ ```javascript
95
+ var result = V8.MongoDb.DelFormDataByWhere({
96
+ DbName: 'diy_chat_' + V8.OsClient.toLowerCase(),
97
+ TableName: 'chat_last_contact',
98
+ _Where: [
99
+ ['UserId', '=', V8.CurrentUser.Id],
100
+ ['ContactUserId', '=', V8.Param.PeerUserId]
101
+ ]
102
+ });
103
+ ```
104
+
105
+ 删除条件必须包含当前权威用户/资源边界,不能只用可伪造的前端参数。返回值的 `Data` 包含 `DeletedCount`。
106
+
107
+ ## 查询单个文档
108
+
109
+ ```javascript
110
+ var result = V8.MongoDb.GetFormData({
111
+ DbName: 'sys_log_2024',
112
+ TableName: 'log_2024_12',
113
+ Id: V8.Param.id // 必传
114
+ });
115
+ ```
116
+
117
+ `GetFormData` 的原生不存在结果是 `{ Code: 1, Data: null }`;只有 `Code=1` 且 `Data` 是文档时才表示找到记录。不要套用 `V8.FormEngine.GetFormData` 的 `Code=2` 约定。查询失败、异常、空响应或缺失 `Data` 字段不能当作记录不存在并继续新增。兼容旧适配器时,仅接受 `Code=2` 且没有正文的明确不存在结果。
118
+
119
+ 聊天等幂等写入先使用固定业务标识定位分区;首次不存在时才新增。Mongo 写入结果未知时只回读同一 `_id` 并比对完整载荷摘要,禁止换 Id 或月份盲重发。正文已持久化但联系人、实时推送或后置 Hook 失败时保留已提交事实;业务层分别返回投影警告,不能宣称消息没有写入。
120
+
121
+ ## 查询文档列表
122
+
123
+ ```javascript
124
+ var result = V8.MongoDb.GetTableData({
125
+ DbName: 'sys_log_2024',
126
+ TableName: 'log_2024_12',
127
+ _Where: [
128
+ ['Type', '=', '访问菜单'],
129
+ ['OR', 'Type', '=', '点击V8按钮']
130
+ ],
131
+ _OrderBy: 'CreateTime',
132
+ _OrderByType: 'DESC',
133
+ _PageIndex: 1,
134
+ _PageSize: 20
135
+ });
136
+ ```
137
+
138
+ `GetFormData` 和 `GetTableData` 属于 dynamic 无模式读取。服务端会在 MongoDB 投影阶段过滤 BSON 内部 `_t` CLR 类型判别字段,避免存量强类型 C# 写入留下的旧类型名称触发反序列化失败。`_t` 不是 V8 业务契约;业务需要类型标记时应使用自有字段(例如 `DocumentType`),不得读取、筛选或依赖 `_t`。强类型 C# MongoDB 模型仍按自身的多态映射处理。
139
+
140
+ ### 原生 `_id` 过滤
141
+
142
+ `_Where: [['_id', 'In', ids]]` 支持原生 ObjectId 的数组或逗号分隔字符串,每次 1–1000 项。`=`、`!=`、范围比较与 `NotIn` 同样使用原生 ObjectId;每项必须是合法的 24 位十六进制标识。无效值返回失败,不能忽略条件后退化成全表查询。普通业务字符串 Id 应使用自有字段,不要伪装成原生 `_id`。
143
+
144
+ ## 跨年跨月游标分页
145
+
146
+ 海量聊天/日志不要只查当前月份,不要逐月 `Count + Skip` 或一次加载全历史。使用 `GetPartitionedTableData` 存储原子,接口引擎继续负责 DiyToken、成员资格、消息双方、业务权限与公开 DTO。平台 SignalR 聊天必须继续调用应用商城拥有的 `platform-chat-runtime`,不能另写业务 Controller。
147
+
148
+ ```javascript
149
+ // 必须先完成业务权限校验;身份来自当前 V8 上下文,前缀来自可信代码。
150
+ var result = V8.MongoDb.GetPartitionedTableData({
151
+ DatabasePrefix: 'audit_log', TablePrefix: 'event',
152
+ _Where: [['UserId', '=', V8.CurrentUser.Id]],
153
+ IndexFields: ['UserId'],
154
+ PageSize: 30, MaxPartitions: 64,
155
+ Cursor: V8.Param.Cursor || ''
156
+ });
157
+ if (result.Code !== 1) return result;
158
+ // result.Data: { Rows, HasMore, NextCursor, ScannedPartitions }
159
+ // 对外返回前显式选择业务字段,不能透传内部 _PartitionDb / _PartitionTable。
160
+ return { Code: 1, Data: {
161
+ Rows: result.Data.Rows.map(function(row) {
162
+ return { Id: row._id, CreateTime: row.CreateTime, Action: row.Action };
163
+ }),
164
+ HasMore: result.Data.HasMore, NextCursor: result.Data.NextCursor
165
+ }};
166
+ ```
167
+
168
+ - 命名:只发现当前租户的 `{DatabasePrefix}_{tenant小写}_{yyyy}` 和兼容旧库 `{DatabasePrefix}_{tenant小写}`;集合为 `{TablePrefix}_{yyyyMM}`、`{TablePrefix}_{yyyy_MM}` 或旧 `{TablePrefix}_{yyyy}`。年度库与集合年份必须一致。不能传任意库/集合列表,不能用普通用户输入控制前缀或索引。
169
+ - `PageSize` 默认 30,范围 1–100(不是 `_PageSize`);`MaxPartitions` 默认 64,范围 1–128。目录最多 200 个租户库、2400 个有效集合。总调用限时 20 秒,单个集合查询限时 10 秒;超限/存储故障返回失败,不能冒充历史结束。
170
+ - `_Where` 必须非空且有效;双向聊天可用 `_WhereAny` 传 1–4 组非空条件,组内 AND、组间 OR。指定 `_WhereAny` 时不再合并 `_Where`,每个分支都必须独立包含权威身份/资源边界。
171
+ - `IndexFields` 可选,最多 3 个互异安全字段;按这些字段升序加 `CreateTime DESC, _id DESC` 创建复合索引。文档必须使用 BSON 日期 `CreateTime` 和原生 ObjectId `_id`。稳定排序按两者倒序,页内旧/新分区重复 `_id` 合并;普通页不执行 Count。
172
+ - `Cursor` 是服务端返回、绑定租户/前缀/过滤条件的 opaque 字符串,最大 2048 字符。它是翻页位置而非鉴权凭据,禁止客户端解析或替换为页码。查询条件改变必须清空游标。即使 `Rows=[]`,只要 `HasMore=true` 仍需用新的 `NextCursor` 继续;跨空月、跨年和旧年度表不能提前截止。
173
+ - `CountOnly:true` 返回 `{ Count }`,仍执行权限条件,扫描范围超过 `MaxPartitions` 直接失败而不返回部分总数。它计数物理行,迁移时不要复制未读事实到多个分区;需要业务去重计数时由权威索引另行维护。
174
+ - 新消息按原始发生时间选择年度库/月度集合。`AddFormData` 的可选顶层 `OccurredAt` 用于可信后端重放保持 `CreateTime`,不得直接信任客户端时间;默认仍使用服务端当前时间。跨月重试必须用稳定业务 Id 和持久分区定位复用原始事实,不能在新月份再写一条。
175
+ - 前端采用滚动异步加载、稳定 Id 合并、请求代际隔离和向前插入锚点补偿。实时消息只增量合并;已读回执读取有界最新页,不能重置旧历史游标或把未展示的全历史标为已读。
176
+
177
+ 该原子需部署相应 Core/MongoDB/API 组件并更新 Managed 应用运行时。源码测试不等于线上 MongoDB、SignalR 或浏览器验收;至少覆盖跨月、跨年、空月、同时间多消息、旧年度集合、重复迁移数据、跨租户拒绝、断线重试和滚动位置。
178
+
179
+ ## 实战模式
180
+
181
+ ### 物理审计与权威索引分页
182
+
183
+ `GetPartitionedTableData` 的高级模式需在可信接口引擎完成业务权限校验后使用,不能把客户端参数直接作为库、集合或索引定义:
184
+
185
+ - `PhysicalRows:true` 保留同 Id 的所有物理副本,按分区和 `_id` 扫描。`PageSize` 默认/上限 100,`MaxPartitions` 默认/上限 8;不接受 `_WhereAny` 或 `CountOnly`。只有省略 `_Where` 的完整扫描才有 `FullPhysicalScope=true`,带条件的扫描不能证明全租户迁移完成。
186
+ - 物理扫描返回 `DirectoryHash/NextCursor/HasMore`,继续时原样带回;目录或集合身份变化、非法 `_id` 必须失败关闭,不得跳过再宣称迁移完成。
187
+ - `CollectionPage:true` 使用可信 `DatabasePrefix/TableName`,`IndexFields` 为 1–4 个字段,`_Where` 必须完整等值匹配这些前缀。`SortField` 是不在前缀内的文本字段,与原生 `_id` 倒序分页。`PageSize` 默认 30、上限 100,普通页不计数。
188
+ - 索引必须在维护阶段用 `EnsureIndex:true` 显式准备;普通读取仅 Hint 已存在的索引。`CountOnly:true` 单独执行索引计数;准备与计数不接受游标。不把首次用户页面加载变成全量索引构建。
189
+ - 两种模式互斥,返回的 `_PartitionDb/_PartitionTable` 仅供可信内部逻辑,公开 DTO 显式选字段。
190
+
191
+ 平台聊天迁移通过固定 Managed `platform-chat-maintenance` 编排。`V8.Method.ManageManagedStorageMaintenance` / `V8.Method.RequireManagedStorageMaintenance` 只接受真实当前租户、固定 Key、超级管理员及非访问密钥会话;普通 V8 MongoDB CRUD 不得读写宿主准入集合。先核实所有写节点升级,再关闭准入、真实排空、分批迁移、完整验证、条件释放;具体流程见 `../message-notification/references/contracts.md`。不能用客户端布尔值、TTL 或清空票据冒充排空。
192
+
193
+ ### IoT 设备日志存储
194
+
195
+ ```javascript
196
+ // 接收 MQTT 消息后存入 MongoDB
197
+ var eventName = V8.EventName;
198
+ if (eventName === 'MessageReceived') {
199
+ V8.MongoDb.AddFormData({
200
+ DbName: 'iot_data',
201
+ TableName: 'device_log_' + DateNow('yyyy_MM'),
202
+ _FormData: {
203
+ DeviceId: V8.MQTT.ClientId,
204
+ Topic: V8.MQTT.Topic,
205
+ Payload: V8.MQTT.Payload,
206
+ Timestamp: DateNow('yyyy-MM-dd HH:mm:ss')
207
+ }
208
+ });
209
+ }
210
+ ```
211
+
212
+ ### 操作审计日志
213
+
214
+ ```javascript
215
+ // 在 SubmitAfterServerV8.js 中记录审计日志到 MongoDB
216
+ V8.MongoDb.AddFormData({
217
+ DbName: 'audit_log',
218
+ TableName: 'form_audit_' + DateNow('yyyy'),
219
+ _FormData: {
220
+ TableName: V8.TableModel.Name,
221
+ Action: V8.FormSubmitAction,
222
+ DataId: V8.Form.Id,
223
+ UserId: V8.CurrentUser.Id,
224
+ UserName: V8.CurrentUser.Name,
225
+ OldData: V8.FormSubmitAction === 'Update' ? JSON.stringify(V8.OldForm) : null,
226
+ NewData: JSON.stringify(V8.Form),
227
+ CreateTime: DateNow('yyyy-MM-dd HH:mm:ss')
228
+ }
229
+ });
230
+ ```
231
+
232
+ ### 按月分表查询
233
+
234
+ ```javascript
235
+ // 查询指定月份的日志
236
+ var month = V8.Param.month || DateNow('yyyy_MM');
237
+ var result = V8.MongoDb.GetTableData({
238
+ DbName: 'sys_log_2024',
239
+ TableName: 'log_' + month,
240
+ _Where: [
241
+ ['UserId', '=', V8.CurrentUser.Id]
242
+ ]
243
+ });
244
+
245
+ return { Code: 1, Data: result };
246
+ ```
247
+
248
+ ## 注意事项
249
+
250
+ - MongoDB 参数统一使用**对象格式**:`{ DbName, TableName, Id, _FormData, _Where, _OrderBy, _OrderByType }`
251
+ - `DbName` 是 MongoDB 数据库名,`TableName` 是集合名
252
+ - `_Where` 条件语法与 `V8.FormEngine` 一致
253
+ - 批量写入仅接受安全字段名、已知操作符和非空条件;条件中的租户、用户和资源 Id 应来自 `V8.OsClient` / `V8.CurrentUser` / 权威回查,不得信任 `V8.Param` 中的同名身份字段
254
+ - 非主库 V8 运行时会把 MongoDB 操作绑定到当前租户;显式传入其它 `OsClient` 不能跨租户
255
+ - 适合存储日志、IoT 数据、大文档等非结构化 / 海量数据
256
+ - 建议按时间分库分表(如 `log_2024_01`),便于清理历史数据
257
+ - MongoDB 操作不参与 `V8.DbTrans` 事务。批量写入 `Code=1` 后即是已提交事实;后续 Hook/投递失败应返回警告或进入补偿,不得返回“未发生”导致盲目重试,重试必须有稳定业务 Id 幂等