增加修复数据的脚本

This commit is contained in:
CounterFire2023 2024-04-23 09:52:30 +08:00
parent 2dc526796d
commit f2da3f1b57
8 changed files with 1384 additions and 3 deletions

1033
initdatas/chest_id.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,9 @@
"lint": "eslint --ext .ts src/**",
"format": "eslint --ext .ts src/** --fix",
"initdata": "ts-node src/initdata.ts",
"repairdata": "ts-node -r tsconfig-paths/register src/repairdata.ts",
"repairdata2": "ts-node -r tsconfig-paths/register src/repairdata2.ts",
"repairredis": "ts-node -r tsconfig-paths/register src/repairredis.ts",
"test:watch": "jest --watch",
"test": "jest"
},

View File

@ -375,7 +375,17 @@ class GameController extends BaseController {
// updateData['$inc']['maxNoChestCount'] = step
// }
// }
await ActivityGame.updateOne({ user: user.id, activity: user.activity }, updateData)
let saveRes = await ActivityGame.findOneAndUpdate(
{ user: user.id, activity: user.activity, tickets: { $gte: step } },
updateData,
{
new: false,
upsert: false,
includeResultMetadata: true,
},
)
// TODO:: check saveRes
console.log(saveRes)
await updateRankScore({
user: user.id,
score: score,

View File

@ -0,0 +1,20 @@
import { dbconn } from 'decorators/dbconn'
import { getModelForClass, index, modelOptions, mongoose, prop } from '@typegoose/typegoose'
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
import { BaseModule } from './Base'
/**
*
*/
@dbconn()
@index({ type: 1 }, { unique: false })
@modelOptions({
schemaOptions: { collection: 'delete_record', timestamps: true },
options: { allowMixed: Severity.ALLOW },
})
export class DeleteRecordClass extends BaseModule {
@prop()
public type: string
@prop({ type: mongoose.Schema.Types.Mixed })
public data: any
}
export const DeleteRecord = getModelForClass(DeleteRecordClass, { existingConnection: DeleteRecordClass['db'] })

96
src/repairdata.ts Normal file
View File

@ -0,0 +1,96 @@
import mongoose from 'mongoose'
import * as dotenv from 'dotenv'
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
dotenv.config({ path: envFile })
console.log(process.env.DB_MAIN)
import { ActivityChest } from 'models/ActivityChest'
import { VoucherRecord } from 'models/VoucherRecord'
import { NFTHolderRecord } from 'models/NFTHodlerRecord'
import { TicketRecord } from 'models/TicketRecord'
const db = mongoose.connection
;(async () => {
try {
await mongoose.connect(process.env.DB_MAIN)
let chests = await ActivityChest.find({})
// 过滤掉箱子码开出来的箱子
console.log('箱子总数: ', chests.length)
let voucherChestSet = new Set()
let voucherRecords = await VoucherRecord.find({ status: 9 })
for (let record of voucherRecords) {
if (record.chests.length > 0) {
voucherChestSet.add(record.chests[0])
}
}
let chestsLeft = []
for (let chest of chests) {
if (!voucherChestSet.has(chest.id)) {
chestsLeft.push(chest)
}
}
console.log('过滤掉箱子码开出来的箱子: ', voucherChestSet.size, '剩余: ', chestsLeft.length)
// 过滤掉正常合作伙伴nft holeder的箱子
let nftHolderRecords = await NFTHolderRecord.find({})
let nftHolderChestSet = new Set()
for (let record of nftHolderRecords) {
if (record.rewards.length > 0) {
nftHolderChestSet.add(record.rewards[0])
}
}
let chestsLeft2 = []
for (let chest of chestsLeft) {
if (!nftHolderChestSet.has(chest.id)) {
chestsLeft2.push(chest)
}
}
console.log('过滤掉正常NFT holder记录的箱子: ', nftHolderChestSet.size, '剩余: ', chestsLeft2.length)
// 根据探索记录时间和箱子生成时间过滤正常的箱子
let ticketRecords = await TicketRecord.find({ score: { $lt: 0 } })
let exploreChestSet = new Set()
for (let ticketRecord of ticketRecords) {
// query chest createAt between ticketRecord.createAt and ticketRecord.createAt - 1 second
let total = Math.abs(ticketRecord.score)
let chestArr = []
for (let chest of chestsLeft2) {
if (
chest.user === ticketRecord.user &&
// @ts-ignore
chest.createdAt < ticketRecord.createdAt &&
// @ts-ignore
chest.createdAt > ticketRecord.createdAt - 1000
) {
chestArr.push(chest)
}
}
// 有限保留已开过和品质高的箱子
chestArr.sort((a, b) => {
return b.status - a.status
})
let count = 0
for (let chest of chestArr) {
if (count >= total) {
break
}
exploreChestSet.add(chest.id)
count++
}
}
let chestsLeft3 = []
for (let chest of chestsLeft2) {
if (!exploreChestSet.has(chest.id)) {
chestsLeft3.push(chest)
}
}
console.log(chestsLeft3.length)
console.log('过滤掉探索获得的箱子: ', exploreChestSet.size, '剩余: ', chestsLeft3.length)
let file = require('fs')
let ids = chestsLeft3.map(chest => chest.id)
file.writeFileSync('initdatas/chest_id.txt', ids.join('\n'))
console.log('Finished repair box data in the database')
} catch (e) {
console.log(e)
}
process.exit(0)
})()

123
src/repairdata2.ts Normal file
View File

@ -0,0 +1,123 @@
import mongoose from 'mongoose'
import * as dotenv from 'dotenv'
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
dotenv.config({ path: envFile })
console.log(process.env.DB_MAIN)
import { ActivityChest } from 'models/ActivityChest'
import { ScoreRecord } from 'models/ScoreRecord'
import { DeleteRecord } from 'models/DeleteRecord'
import { rankKey, updateRank, updateRankInvite } from 'services/rank.svr'
import { ZRedisClient } from 'zutils'
import { RANK_SCORE_SCALE } from 'common/Constants'
const db = mongoose.connection
const updateRedis = async (activity, user, score) => {
const key = rankKey(activity)
await updateRank(key, score, user)
}
const updateRedisInvite = async (activity, sourceUser, user, score) => {
const keyInvite = `${activity}:invite`
await updateRankInvite(keyInvite, parseInt(score * RANK_SCORE_SCALE + ''), `${sourceUser}_${user}`)
}
;(async () => {
try {
return false
let fs = require('fs')
let ids = fs.readFileSync('initdatas/chest_id.txt', 'utf-8').split('\n')
let ids2 = []
for (let i = 0; i < ids.length; i++) {
if (ids[i].trim()) {
ids2.push(ids[i])
}
}
let chests = await ActivityChest.find({ _id: { $in: ids2 } })
const activity = 'uaw_activity'
console.time('delete')
let opts = { url: process.env.REDIS }
new ZRedisClient(opts)
for (let chest of chests) {
if (chest.status === 1) {
// 未开启
// 处理助力分数
if (chest.bonusUsers.length > 0) {
for (let user of chest.bonusUsers) {
let record = await ScoreRecord.findOne({ user: user, activity: chest.activity, type: 'enhance_chest_gift' })
console.log('助力分数: ', record.score)
await updateRedis(activity, user, -record.score)
let dRecord = new DeleteRecord({
type: 'enhance_chest_gift',
data: record,
})
await dRecord.save()
await ScoreRecord.deleteOne({ _id: record.id })
}
}
} else if (chest.status === 9) {
// 已开启
// 处理助力分数
if (chest.bonusUsers.length > 0) {
for (let user of chest.bonusUsers) {
let record = await ScoreRecord.findOne({ user: user, activity: chest.activity, type: 'enhance_chest_gift' })
console.log('助力分数: ', record.score)
// update redis
await updateRedis(activity, user, -record.score)
let dRecord = new DeleteRecord({
type: 'enhance_chest_gift',
data: record,
})
await dRecord.save()
await ScoreRecord.deleteOne({ _id: record.id })
}
}
// 处理已开箱所得分数
let record = await ScoreRecord.findOne({
'data.chestId': chest.id,
user: chest.user,
activity: chest.activity,
type: 'open_chest',
})
console.log('开箱所得分数: ', record.score)
// update redis
await updateRedis(activity, chest.user, -record.score)
let dRecord = new DeleteRecord({
type: 'open_chest',
data: record,
})
await dRecord.save()
await ScoreRecord.deleteOne({ _id: record.id })
// 处理邀请者所得分数
let subRecords = await ScoreRecord.find({
'data.fromUser': record.user,
'data.chestId': chest.id,
type: 'invite_rebate',
})
for (let subRecord of subRecords) {
console.log('邀请者所得分数: ', subRecord.score, subRecord.id)
// update redis
await updateRedis(activity, subRecord.user, -record.score)
await updateRedisInvite(activity, record.user, subRecord.user, -record.score)
let dRecord = new DeleteRecord({
type: 'invite_rebate',
data: subRecord,
})
await dRecord.save()
await ScoreRecord.deleteOne({ _id: subRecord.id })
}
// 移除当前箱子
}
let dRecordChest = new DeleteRecord({
type: 'chest',
data: chest,
})
await dRecordChest.save()
await ActivityChest.deleteOne({ _id: chest.id })
}
console.timeEnd('delete')
} catch (e) {
console.log(e)
}
process.exit(0)
})()

94
src/repairredis.ts Normal file
View File

@ -0,0 +1,94 @@
import mongoose from 'mongoose'
import * as dotenv from 'dotenv'
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
dotenv.config({ path: envFile })
console.log(process.env.DB_MAIN)
import { ActivityChest } from 'models/ActivityChest'
import { ScoreRecord } from 'models/ScoreRecord'
import { DeleteRecord } from 'models/DeleteRecord'
import { rankKey, updateRank, updateRankInvite } from 'services/rank.svr'
import { ZRedisClient } from 'zutils'
import { RANK_SCORE_SCALE } from 'common/Constants'
const db = mongoose.connection
const totalKey = 'uaw_activity:score'
const keyInvite = `uaw_activity:invite`
const updateRedis = async (activity, user, score) => {
await updateRank(totalKey, score, user)
}
const updateRedisInvite = async (activity, sourceUser, user, score) => {
await updateRankInvite(keyInvite, parseInt(score * RANK_SCORE_SCALE + ''), `${sourceUser}_${user}`)
}
const updateRedis2 = (key, vals) => {
return new Promise((resolve, reject) => {
new ZRedisClient().pub.zadd(key, vals, function (err, res) {
if (err) {
reject(err)
} else {
resolve(res)
}
})
})
}
;(async () => {
return false
try {
let records = await ScoreRecord.aggregate([{ $group: { _id: '$user', count: { $sum: '$score' } } }])
console.time('first')
// _id, count
console.log('records: ', records.length)
let opts = { url: process.env.REDIS }
new ZRedisClient(opts)
let vals = []
for (let i = 0, l = records.length; i < l; i++) {
vals.push(records[i].count * 100 + 1 - Date.now() / 1000 / 10000000000)
vals.push(records[i]._id)
if (i++ % 1000 === 0) {
await updateRedis2(totalKey, vals)
vals.length = 0
}
}
if (vals.length > 0) {
await updateRedis2(totalKey, vals)
}
console.timeEnd('first')
let records2 = await ScoreRecord.aggregate([
{ $match: { type: 'invite_rebate' } },
{
$group: {
_id: {
user: '$user',
from: '$data.fromUser',
},
count: { $sum: '$score' },
},
},
])
console.time('second')
// _id, count
console.log('records2: ', records2.length)
let vals2 = []
for (let i = 0, l = records.length; i < l; i++) {
vals2.push(records[i].count * 100)
vals2.push(`${records[i]._id.from}_${records[i]._id.user}`)
if (i++ % 1000 === 0) {
await updateRedis2(keyInvite, vals2)
vals2.length = 0
}
}
if (vals2.length > 0) {
await updateRedis2(keyInvite, vals2)
}
console.timeEnd('second')
} catch (e) {
console.log(e)
}
console.log('end')
process.exit(0)
})()

View File

@ -68,7 +68,7 @@ export const updateRankScore = async ({
* @param score
* @param member
*/
const updateRank = async (key: string, score: number, member: string) => {
export const updateRank = async (key: string, score: number, member: string) => {
let scoreSaved = (await new ZRedisClient().zscore(key, member)) + ''
if (scoreSaved) {
scoreSaved = scoreSaved.substring(0, scoreSaved.indexOf('.'))
@ -76,10 +76,12 @@ const updateRank = async (key: string, score: number, member: string) => {
let scoreOld = parseInt(scoreSaved || '0')
score = score * RANK_SCORE_SCALE + scoreOld
const scoreToSave = score + 1 - Date.now() / 1000 / 10000000000
let vals = ['1', '2']
new ZRedisClient().pub.zadd(...vals)
await new ZRedisClient().zadd(key, scoreToSave, member)
}
const updateRankInvite = async (key: string, score: number, member: string) => {
export const updateRankInvite = async (key: string, score: number, member: string) => {
await new ZRedisClient().zincrby(key, score, member)
}