集合:用户事件(events)
字数
1066 字
阅读时间
5 分钟
1. 目的与使用场景
- 存储前端埋点与关键行为流水,支撑实时看板、画像更新、A/B 实验。事件定义参考《埋点与数据分析.md》。由前端
wx.reportAnalytics、事件收集云函数写入,数据团队读取。
2. Schema 定义
| 字段 | 类型 | 必填 | 默认值 | 约束/校验 | 说明 | 隐私分级 |
|---|---|---|---|---|---|---|
| _id | string | 是 | - | TCB 自动 | 主键 | P2 |
| user_id | 指针id | 否 | - | 指向 users._id | 用户 | P2 |
| openid_hash | string | 是 | - | 长度 32 | openid 哈希 | P2 |
| event_name | string | 是 | - | 参考事件枚举 | 事件名称 | P1 |
| event_time | date | 是 | - | ISO 字符串 | 事件时间 | P1 |
| page_path | string | 否 | - | 小程序路径 | 触发页面 | P1 |
| event_params | object | 是 | - | - | 事件参数 | P2 |
| device | object | 否 | - | {model, system} | 设备信息 | P1 |
| app_version | string | 否 | - | semver | 客户端版本 | P1 |
| env | string | 否 | prod | 枚举(prod,staging,test) | 环境 | P1 |
| network_type | string | 否 | - | 枚举(wifi,4g,5g,unknown) | 网络 | P1 |
| session_id | string | 否 | - | 长度 ≤ 64 | 会话 ID | P1 |
| trace_id | string | 否 | - | 长度 ≤ 64 | 链路追踪 | P1 |
| source_type | string | 否 | client | 枚举(client,server) | 上报来源 | P1 |
| exp_group | string | 否 | - | 长度 ≤ 32 | 实验分组 | P1 |
| createdAt | date | 是 | - | 服务端时间 | 写入时间 | P1 |
3. 索引与唯一约束
- 单字段索引:
event_name、event_time - 复合索引:
[user_id, event_time desc]、[event_name, event_time desc] - 唯一性约束:
[openid_hash, event_time, event_name, trace_id](可选) - 设计理由:画像更新需按用户最近事件;报表按事件名聚合;trace 防止重复写入。
4. 访问控制(TCB 权限)
json
{
"read": "auth.role in ['data','ops']",
"write": "auth.role in ['event_ingestor']"
}数据团队和运维可读取;写入仅限事件采集服务。
- 关系与级联
user_id→users- 与
suggestions、tasks、reports通过事件参数关联 - 删除策略:保留原始事件,不进行级联删除;用户注销时可脱敏 openid_hash。
- 反范式:
event_params保留原样 JSON 方便上游解析。
- 数据生命周期与合规
- 留存:原始事件保留 1 年;超过时段转存至对象存储并删除集合中的详情。
- 匿名化:使用 openid 哈希,必要时移除
user_id。 - 审计:
createdAt、source_type;对高敏事件(如risk_signal_escalate)加密存储参数。
API/云函数契约映射 | 接口/函数 | 读/写 | 使用字段 | 过滤条件 | 排序/分页 | 备注 | | 事件收集云函数
ingestEvent| 写 | openid_hash, user_id, event_name, event_time, event_params, session_id, trace_id | - | - | 前端上报入口 | | 行为画像任务updateProfile| 读 | user_id, event_name, event_params |event_time >= now-7d| - | 调整建议权重 | | 数据看板导出exportEvents| 读 | event_name, event_time, event_params | 时间范围 |event_time asc| 统计分析 |示例文档(≥3条)
json
{
"_id": "evt_9001",
"user_id": "usr_001",
"openid_hash": "a1b2c3d4",
"event_name": "mood_checkin_submit",
"event_time": "2024-04-06T09:00:02Z",
"page_path": "miniprogram/pages/today/index",
"event_params": {"mood_score": 72, "primary_emotion": "calm", "mood_tags": ["校园", "自习室"], "input_type": "mood_card"},
"device": {"model": "iPhone 14", "system": "iOS 17"},
"app_version": "1.3.0",
"env": "prod",
"network_type": "wifi",
"session_id": "sess_abcd",
"trace_id": "trace_1001",
"createdAt": "2024-04-06T09:00:03Z"
}
{
"_id": "evt_9050",
"user_id": "usr_001",
"openid_hash": "a1b2c3d4",
"event_name": "suggestion_task_create",
"event_time": "2024-04-06T09:01:00Z",
"page_path": "miniprogram/pages/today/index",
"event_params": {"suggestion_id": "sg_001", "task_id": "task_305", "category": "relationship", "source": "model"},
"app_version": "1.3.0",
"env": "prod",
"session_id": "sess_abcd",
"trace_id": "trace_1001",
"createdAt": "2024-04-06T09:01:01Z"
}
{
"_id": "evt_9500",
"user_id": "usr_002",
"openid_hash": "z9y8x7w6",
"event_name": "risk_signal_escalate",
"event_time": "2024-04-06T14:04:05Z",
"event_params": {"risk_signal_id": "sos_20240406_01", "source": "treehole", "severity_level": "R3", "handler_role": "counselor"},
"env": "prod",
"network_type": "4g",
"trace_id": "trace_sos_01",
"createdAt": "2024-04-06T14:04:05Z"
}- 常用查询样例(≥3条)
javascript
// 近 7 天情绪打卡次数
const checkinCount = await db.collection('events').where({
user_id: auth.uid,
event_name: 'mood_checkin_submit',
event_time: db.command.gte(new Date(Date.now() - 7 * 86400000).toISOString())
}).count();
// 统计建议接受率
const acceptedEvents = await db.collection('events').where({
event_name: 'suggestion_task_create',
event_time: db.command.gte(new Date(Date.now() - 30 * 86400000).toISOString())
}).get();
// 风险监控查询
const riskEvents = await db.collection('events').where({
event_name: 'risk_signal_escalate',
event_time: db.command.gte(new Date(Date.now() - 24 * 3600 * 1000).toISOString())
}).orderBy('event_time', 'desc').get();- 边界与错误码
- 重复上报:命中唯一约束返回
E_EVENT_DUPLICATE。 - 参数缺失:缺少必填字段返回
E_EVENT_INVALID_PAYLOAD。 - 越权读取:非数据/运维角色返回
E_FORBIDDEN。
- 变更影响评估
- 新事件需同步《埋点与数据分析.md》、数据仓库 schema、画像服务逻辑。
- 索引变更影响实时看板延迟与批处理成本。
- 假设与待确认
- 假设 openid 哈希由前端计算;待确认是否改为云函数统一脱敏。
- 待确认事件是否需要 geo 信息字段。