1
1
mirror of https://github.com/ZeroCatDev/ClassworksKV.git synced 2025-12-07 21:13:10 +00:00

feat: 实现批量upsert方法,优化键值对处理性能

This commit is contained in:
Sunwuyuan 2025-12-07 13:33:47 +08:00
parent e65f84aa22
commit 21d6ddf164
No known key found for this signature in database
GPG Key ID: A6A54CF66F56BB64
2 changed files with 104 additions and 35 deletions

View File

@ -298,43 +298,25 @@ router.post(
req.connection.socket?.remoteAddress ||
"";
const results = [];
const errorList = [];
// 批量处理所有键值对
for (const [key, value] of Object.entries(data)) {
try {
const result = await kvStore.upsert(deviceId, key, value, creatorIp);
results.push({
key: result.key,
created: result.createdAt.getTime() === result.updatedAt.getTime(),
});
// 广播每个键的变更
const uuid = res.locals.device?.uuid;
if (uuid) {
broadcastKeyChanged(uuid, {
key: result.key,
action: "upsert",
created: result.createdAt.getTime() === result.updatedAt.getTime(),
updatedAt: result.updatedAt,
batch: true,
});
}
} catch (error) {
errorList.push({
key,
error: error.message,
});
}
}
// 使用优化的批量upsert方法
const { results, errors: errorList } = await kvStore.batchUpsert(deviceId, data, creatorIp);
return res.status(200).json({
deviceId,
total: Object.keys(data).length,
successful: results.length,
failed: errorList.length,
results,
errors: errorList.length > 0 ? errorList : undefined,
code: 200,
message: "批量导入成功",
data: {
deviceId,
summary: {
total: Object.keys(data).length,
successful: results.length,
failed: errorList.length,
},
results: results.map(r => ({
key: r.key,
isNew: r.created,
})),
...(errorList.length > 0 && { errors: errorList }),
},
});
})
);

View File

@ -102,6 +102,62 @@ class KVStore {
};
}
/**
* 批量创建或更新键值对优化性能
* @param {number} deviceId - 设备ID
* @param {object} data - 键值对数据 {key1: value1, key2: value2, ...}
* @param {string} creatorIp - 创建者IP可选
* @returns {object} {results: Array, errors: Array}
*/
async batchUpsert(deviceId, data, creatorIp = "") {
const results = [];
const errors = [];
// 使用事务处理所有操作
await prisma.$transaction(async (tx) => {
for (const [key, value] of Object.entries(data)) {
try {
const item = await tx.kVStore.upsert({
where: {
deviceId_key: {
deviceId: deviceId,
key: key,
},
},
update: {
value,
...(creatorIp && {creatorIp}),
},
create: {
deviceId: deviceId,
key: key,
value,
creatorIp,
},
});
results.push({
key: item.key,
created: item.createdAt.getTime() === item.updatedAt.getTime(),
createdAt: item.createdAt,
updatedAt: item.updatedAt,
});
} catch (error) {
errors.push({
key,
error: error.message,
});
}
}
});
// 在事务完成后,一次性更新指标
const totalKeys = await prisma.kVStore.count();
keysTotal.set(totalKeys);
return { results, errors };
}
/**
* 通过设备ID和键名删除
* @param {number} deviceId - 设备ID
@ -219,6 +275,37 @@ class KVStore {
});
return count;
}
/**
* 获取指定设备的统计信息
* @param {number} deviceId - 设备ID
* @returns {object} 统计信息
*/
async getStats(deviceId) {
const [totalKeys, oldestKey, newestKey] = await Promise.all([
prisma.kVStore.count({
where: { deviceId },
}),
prisma.kVStore.findFirst({
where: { deviceId },
orderBy: { createdAt: "asc" },
select: { createdAt: true, key: true },
}),
prisma.kVStore.findFirst({
where: { deviceId },
orderBy: { updatedAt: "desc" },
select: { updatedAt: true, key: true },
}),
]);
return {
totalKeys,
oldestKey: oldestKey?.key,
oldestCreatedAt: oldestKey?.createdAt,
newestKey: newestKey?.key,
newestUpdatedAt: newestKey?.updatedAt,
};
}
}
export default new KVStore();