mirror of
https://github.com/ZeroCatDev/ClassworksKV.git
synced 2025-12-08 22:53:10 +00:00
feat: 实现批量upsert方法,优化键值对处理性能
This commit is contained in:
parent
e65f84aa22
commit
21d6ddf164
@ -298,43 +298,25 @@ router.post(
|
|||||||
req.connection.socket?.remoteAddress ||
|
req.connection.socket?.remoteAddress ||
|
||||||
"";
|
"";
|
||||||
|
|
||||||
const results = [];
|
// 使用优化的批量upsert方法
|
||||||
const errorList = [];
|
const { results, errors: errorList } = await kvStore.batchUpsert(deviceId, data, creatorIp);
|
||||||
|
|
||||||
// 批量处理所有键值对
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
deviceId,
|
code: 200,
|
||||||
total: Object.keys(data).length,
|
message: "批量导入成功",
|
||||||
successful: results.length,
|
data: {
|
||||||
failed: errorList.length,
|
deviceId,
|
||||||
results,
|
summary: {
|
||||||
errors: errorList.length > 0 ? errorList : undefined,
|
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 }),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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和键名删除
|
* 通过设备ID和键名删除
|
||||||
* @param {number} deviceId - 设备ID
|
* @param {number} deviceId - 设备ID
|
||||||
@ -219,6 +275,37 @@ class KVStore {
|
|||||||
});
|
});
|
||||||
return count;
|
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();
|
export default new KVStore();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user