- konga平台跨域问题
- mongo拉数据问题
1. konga平台跨域问题
之前一直用腾讯云的Api网关用来做业务分发,最近上去看到Api网关要废弃了,推荐用云原生Api网关替换,在上面部署了个新业务,从实用性上来说没多大差别,唯一的问题就是一个service和一个后端绑定了,虽然可以配置多个路由,但最终都会指向到一个后端。这就导致一个后端需要建一个service,而我的业务中,基本上都是一个路由对应一个后端,对我来说就比较繁琐。之前Api网关是在配置路由的时候可以选择后端通道的,这样就能随意配置。
另外还有个问题就是云原生Api网关配置跨域比较麻烦,在腾讯云后台还不能直接配置,需要去他提供的konga后台去配置cors插件,而且配置也比较繁琐,也不支持导入导出插件功能,需要一个个手动填,比较麻烦。另外在支持跨域的时候需要在路由那边支持OPTIONS请求,因为我的请求是非简单。具体可以参考这篇文章
2. mongo拉数据问题
新项目上线之后,策划有需求要拉下线上数据。因为用的mongo数据,不太熟悉,而且拉数据方式跟sql不太一样,所以拉起数据来比麻烦,需要写JavaScript脚本,比如拉取次留的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 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
| // 定义起始日期 (UTC+8 时间) var startDate = new Date(2024, 5, 29); // 请根据实际情况调整年份和月份(月份是从0开始的) var endDate = new Date();
// 转换为时间戳 var startTimestamp = startDate.getTime() / 1000; var endTimestamp = Math.floor(endDate.getTime() / 1000); print(startTimestamp); print(endTimestamp);
// 初始化结果数组 var retentionRates = [];
// 循环每一天 var currentTimestamp = startTimestamp; while (currentTimestamp < endTimestamp) { // 查询当天注册的用户 var registrations = db.LogRegister.find({ Day: currentTimestamp }).map(function(r) { return r.PlayerId; }); var registeredUsers = new Set(registrations); var registeredUsersCount = registeredUsers.size; // 查询第二天登录的用户 var logins = db.LogLogin.find({ Day: currentTimestamp + 86400 * 1 }).map(function(l) { return l.PlayerId; }); var loggedInUsers2 = new Set(logins); // 查询第三天登录的用户 logins = db.LogLogin.find({ Day: currentTimestamp + 86400 * 2 }).map(function(l) { return l.PlayerId; }); var loggedInUsers3 = new Set(logins); // 查询第四天登录的用户 logins = db.LogLogin.find({ Day: currentTimestamp + 86400 * 3 }).map(function(l) { return l.PlayerId; }); var loggedInUsers4 = new Set(logins); // 查询第五天登录的用户 logins = db.LogLogin.find({ Day: currentTimestamp + 86400 * 4 }).map(function(l) { return l.PlayerId; }); var loggedInUsers5 = new Set(logins); // 查询第六天登录的用户 logins = db.LogLogin.find({ Day: currentTimestamp + 86400 * 5 }).map(function(l) { return l.PlayerId; }); var loggedInUsers6 = new Set(logins); // 查询第七天登录的用户 logins = db.LogLogin.find({ Day: currentTimestamp + 86400 * 6 }).map(function(l) { return l.PlayerId; }); var loggedInUsers7 = new Set(logins); // 计算留存用户 var retainedUsersCount2 = Array.from(registeredUsers).filter(function(id) { return loggedInUsers2.has(id); }).length; var retainedUsersCount3 = Array.from(registeredUsers).filter(function(id) { return loggedInUsers3.has(id); }).length; var retainedUsersCount4 = Array.from(registeredUsers).filter(function(id) { return loggedInUsers4.has(id); }).length; var retainedUsersCount5 = Array.from(registeredUsers).filter(function(id) { return loggedInUsers5.has(id); }).length; var retainedUsersCount6 = Array.from(registeredUsers).filter(function(id) { return loggedInUsers6.has(id); }).length; var retainedUsersCount7 = Array.from(registeredUsers).filter(function(id) { return loggedInUsers7.has(id); }).length; // 计算留存率 var retentionRate = registeredUsersCount > 0 ? (retainedUsersCount2 / registeredUsersCount) : 0; // 打印结果 var d = new Date(currentTimestamp * 1000); print((d.getMonth() + 1).toString() + "-" + d.getDate() + ", 新增人数: " + registeredUsersCount + ", 次留: " + ((retainedUsersCount2 / registeredUsersCount) * 100).toFixed(2) + "%" + ", 3留: " + ((retainedUsersCount3 / registeredUsersCount) * 100).toFixed(2) + "%" + ", 4留: " + ((retainedUsersCount4 / registeredUsersCount) * 100).toFixed(2) + "%" + ", 5留: " + ((retainedUsersCount5 / registeredUsersCount) * 100).toFixed(2) + "%" + ", 6留: " + ((retainedUsersCount6 / registeredUsersCount) * 100).toFixed(2) + "%" + ", 7留: " + ((retainedUsersCount7 / registeredUsersCount) * 100).toFixed(2) + "%"); // 移动到下一天 currentTimestamp += 86400; }
|
这个可以做优化,可以先把每天注册的用户和登录的用户一次性都拉到,循环里面只做计算即可。
这个看着还好,但是我要拉取某些用户数据的时候就很麻烦,而且不容易看懂。比如我要拉取所有玩家的等级数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| db.Player.aggregate([ { $addFields: { CreateDate: { $dateToString: { format: "%Y-%m-%d", date: { $toDate: { $multiply: ["$CreateTime", 1000] } } } }, LoginDate: { $dateToString: { format: "%Y-%m-%d", date: { $toDate: { $multiply: ["$LoginTime", 1000] } } } } } }, { $match: { $expr: { $gt: [ "$LoginDate", "$CreateDate" ] } } }, { $addFields: { Modules: { $arrayElemAt: [ { $arrayElemAt: [ { $arrayElemAt: ["$Player", 0] }, 3 ] }, 1 ] } } }, // 等级 { $addFields: { BasicModule: { $arrayElemAt: [ { $arrayElemAt: [ { $arrayElemAt: [ "$Modules", 1 ] }, 1 ] }, 0] } } }, { $addFields: { Level: { $arrayElemAt: [ "$BasicModule", 0 ] } } }, { $project: { _id: 0, Gbid: 1, CreateDate: 1, LoginDate: 1, Level: 1 } } ]);
|
里面都是arrayElemAt,不太直观,很容易搞不清楚当前到哪一层了。这里框架这边也有些设计问题在,所有的Dictionary和Object都会转成array来处理,主要原因是因为Mongo不支持int作为key来存数据,然后为了避免单个文档不超过16mb限制(mongo有这个限制),所以每个字段是不存key的,通过代码里面的属性标签来确定到底是array的哪个字段。这样导致的问题就是要找Player某个字段会很麻烦且不直观。这一块后续再想想怎么去优化下框架设计。