云数据库 MongoDB 实践:千里达票务系统游客行为与评价存储
订单、库存这种强事务数据放 RDS MySQL,但游客行为日志、景区评价、收藏记录这种 schema 松散、字段经常变的数据塞 MySQL 就很别扭:加个字段要 ALTER TABLE,一年下来表上加了几十个 nullable 列。这类数据迁到阿里云云数据库 MongoDB,文档模型自由 schema,单集群支持千万级文档。
一、哪些数据适合 MongoDB
- 用户行为流水:浏览、加购、分享,事件结构经常加字段;
- 景区评价:图文、标签、用户回复,结构半结构化;
- 游客收藏/足迹:嵌套数组,不适合 MySQL 多行;
- 搜索日志:原始 query 全量留存做分析。
二、为什么不用 MySQL JSON 字段
早期试过 MySQL 加个 JSON 列,但索引和查询能力都弱:JSON 路径查询慢、不能建复合索引、聚合统计要把数据捞回内存算。MongoDB 原生支持嵌套字段索引和聚合管道,更顺手。
三、关键实现
3.1 评价文档模型
db.reviews.insertOne({
scene_id: "SC1001",
order_no: "O20261001001",
user_id: "U888",
rating: 5,
tags: ["风景好", "取票快"],
images: ["https://oss/1.jpg", "https://oss/2.jpg"],
reply: null,
created_at: ISODate()
})
db.reviews.createIndex({
scene_id: 1, created_at: -1 })
db.reviews.createIndex({
user_id: 1, created_at: -1 })
3.2 聚合统计某景区平均分
db.reviews.aggregate([
{
$match: {
scene_id: "SC1001" } },
{
$group: {
_id: null,
avg: {
$avg: "$rating" },
cnt: {
$sum: 1 } } }
])
3.3 分片
评价表预计千万级,按 scene_id 做分片键,把不同景区数据散到不同分片。
四、踩坑复盘
- JOIN 思维写 MongoDB:早期把评价和用户信息硬塞一个文档,用户改昵称所有评价都要改。解决:只存 user_id,展示时再聚合;
- 没建索引:按 user_id 查评价全表扫描。解决:上线前用 explain() 检查慢查询;
- 文档过大:某条评价塞了 20 张图的 base64,单文档超 16MB。解决:图全走 OSS,文档里只存 URL;
- 备份策略:默认备份保留 7 天,误删数据找不回。解决:关键集合开启 PITR,保留 30 天。
五、效果与总结
MongoDB 迁完后,业务加字段不再需要 DDL,迭代速度明显快了。强事务留在 MySQL,松散数据给 MongoDB,按数据模型选库——这是千里达票务系统上云后最重要的架构原则之一。