feat: 更新 replace-team-qrcode-url 脚本以支持 staff-qrcode 集合的前缀替换
This commit is contained in:
parent
525d9fa1d8
commit
73e9875d40
@ -5,6 +5,8 @@
|
||||
* 目的:
|
||||
* - 扫描 corp.team collection
|
||||
* - 将 team.qrcodes[].qrcode 中旧前缀替换为新前缀
|
||||
* - 扫描 corp.staff-qrcode collection
|
||||
* - 将 staff-qrcode.archiveLink.url 中旧前缀替换为新前缀
|
||||
*
|
||||
* 安全:
|
||||
* - 默认 dry-run(不落库)
|
||||
@ -70,6 +72,7 @@ function createDefaultOptions() {
|
||||
return {
|
||||
dbName: "corp",
|
||||
collection: "team",
|
||||
staffCollection: "staff-qrcode",
|
||||
batchDocs: 200,
|
||||
skipDocs: 0,
|
||||
limitDocs: 0,
|
||||
@ -107,6 +110,7 @@ function parseArgs(argv) {
|
||||
if (!key) return;
|
||||
if (key === "dbname" || key === "db") opts.dbName = value;
|
||||
else if (key === "collection") opts.collection = value;
|
||||
else if (key === "staffcollection") opts.staffCollection = value;
|
||||
else if (key === "mongouri" || key === "mongourl") opts.mongoUri = value;
|
||||
else if (key === "mongourienv") opts.mongoUriEnv = value;
|
||||
else if (key === "mongohost") opts.mongoHost = value;
|
||||
@ -144,6 +148,9 @@ function parseArgs(argv) {
|
||||
} else if (a === "--collection") {
|
||||
opts.collection = takeValue(i);
|
||||
i++;
|
||||
} else if (a === "--staffCollection") {
|
||||
opts.staffCollection = takeValue(i);
|
||||
i++;
|
||||
} else if (a === "--mongoUri" || a === "--mongoUrl" || a === "--mongoURL") {
|
||||
opts.mongoUri = takeValue(i);
|
||||
i++;
|
||||
@ -290,6 +297,75 @@ function updateTeamDoc(doc, { oldPrefix, newPrefix }) {
|
||||
return { changed, nextQrcodes };
|
||||
}
|
||||
|
||||
function updateStaffQrcodeDoc(doc, { oldPrefix, newPrefix }) {
|
||||
const archiveLink =
|
||||
doc && doc.archiveLink && typeof doc.archiveLink === "object"
|
||||
? doc.archiveLink
|
||||
: null;
|
||||
if (!archiveLink) {
|
||||
return { changed: 0, nextArchiveLink: archiveLink };
|
||||
}
|
||||
const current = archiveLink.url;
|
||||
const next = replacePrefix(current, oldPrefix, newPrefix);
|
||||
if (next === current) {
|
||||
return { changed: 0, nextArchiveLink: archiveLink };
|
||||
}
|
||||
return {
|
||||
changed: 1,
|
||||
nextArchiveLink: { ...archiveLink, url: next },
|
||||
};
|
||||
}
|
||||
|
||||
async function processCollectionDocs({
|
||||
collection,
|
||||
filter,
|
||||
batchDocs,
|
||||
sortById,
|
||||
skipDocs,
|
||||
limitDocs,
|
||||
dryRun,
|
||||
updateDoc,
|
||||
buildUpdate,
|
||||
describeDoc,
|
||||
}) {
|
||||
let cursor = collection.find(filter, { batchSize: batchDocs });
|
||||
if (sortById) cursor = cursor.sort({ _id: 1 });
|
||||
if (skipDocs) cursor = cursor.skip(skipDocs);
|
||||
if (limitDocs) cursor = cursor.limit(limitDocs);
|
||||
|
||||
let scanned = 0;
|
||||
let matchedDocs = 0;
|
||||
let replacedUrls = 0;
|
||||
let batchIndex = 0;
|
||||
|
||||
while (await cursor.hasNext()) {
|
||||
const batch = [];
|
||||
while (batch.length < batchDocs && (await cursor.hasNext())) {
|
||||
batch.push(await cursor.next());
|
||||
}
|
||||
if (batch.length === 0) break;
|
||||
batchIndex++;
|
||||
console.log(
|
||||
`[step] ${collection.collectionName} batch#${batchIndex} 读取文档 ${batch.length} 条(已扫描 ${scanned} 条)`
|
||||
);
|
||||
|
||||
for (const doc of batch) {
|
||||
scanned++;
|
||||
const { changed, ...payload } = updateDoc(doc);
|
||||
if (changed === 0) continue;
|
||||
matchedDocs++;
|
||||
replacedUrls += changed;
|
||||
console.log(`[match] ${collection.collectionName} ${describeDoc(doc)} replaced=${changed}`);
|
||||
|
||||
if (!dryRun) {
|
||||
await collection.updateOne({ _id: doc._id }, buildUpdate(payload));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { scanned, matchedDocs, replacedUrls };
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const opts = parseArgs(process.argv);
|
||||
applyEnvFallbacks(opts);
|
||||
@ -336,52 +412,57 @@ async function main() {
|
||||
|
||||
try {
|
||||
const db = client.db(opts.dbName);
|
||||
const col = db.collection(opts.collection);
|
||||
const teamCol = db.collection(opts.collection);
|
||||
const staffCol = db.collection(opts.staffCollection);
|
||||
const filter = {};
|
||||
if (isNonEmptyString(opts.corpId)) filter.corpId = opts.corpId;
|
||||
|
||||
console.log(`[step] collection=${opts.dbName}.${opts.collection} corpId=${opts.corpId || "全部"} mode=${opts.dryRun ? "dry-run" : "apply"}`);
|
||||
let cursor = col.find(filter, { batchSize: opts.batchDocs });
|
||||
if (opts.sortById) cursor = cursor.sort({ _id: 1 });
|
||||
if (opts.skipDocs) cursor = cursor.skip(opts.skipDocs);
|
||||
if (opts.limitDocs) cursor = cursor.limit(opts.limitDocs);
|
||||
|
||||
let scanned = 0;
|
||||
let matchedDocs = 0;
|
||||
let replacedUrls = 0;
|
||||
let batchIndex = 0;
|
||||
|
||||
while (await cursor.hasNext()) {
|
||||
const batch = [];
|
||||
while (batch.length < opts.batchDocs && (await cursor.hasNext())) {
|
||||
batch.push(await cursor.next());
|
||||
}
|
||||
if (batch.length === 0) break;
|
||||
batchIndex++;
|
||||
console.log(`[step] batch#${batchIndex} 读取文档 ${batch.length} 条(已扫描 ${scanned} 条)`);
|
||||
|
||||
for (const doc of batch) {
|
||||
scanned++;
|
||||
const { changed, nextQrcodes } = updateTeamDoc(doc, {
|
||||
console.log(
|
||||
`[step] collection=${opts.dbName}.${opts.collection} corpId=${opts.corpId || "全部"} mode=${opts.dryRun ? "dry-run" : "apply"}`
|
||||
);
|
||||
const teamStats = await processCollectionDocs({
|
||||
collection: teamCol,
|
||||
filter,
|
||||
batchDocs: opts.batchDocs,
|
||||
sortById: opts.sortById,
|
||||
skipDocs: opts.skipDocs,
|
||||
limitDocs: opts.limitDocs,
|
||||
dryRun: opts.dryRun,
|
||||
updateDoc: (doc) =>
|
||||
updateTeamDoc(doc, {
|
||||
oldPrefix: opts.oldPrefix,
|
||||
newPrefix: opts.newPrefix,
|
||||
});
|
||||
if (changed === 0) continue;
|
||||
matchedDocs++;
|
||||
replacedUrls += changed;
|
||||
console.log(`[match] _id=${doc._id} teamId=${doc.teamId || ""} corpId=${doc.corpId || ""} replaced=${changed}`);
|
||||
|
||||
if (!opts.dryRun) {
|
||||
await col.updateOne(
|
||||
{ _id: doc._id },
|
||||
{ $set: { qrcodes: nextQrcodes } }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
buildUpdate: ({ nextQrcodes }) => ({ $set: { qrcodes: nextQrcodes } }),
|
||||
describeDoc: (doc) =>
|
||||
`_id=${doc._id} teamId=${doc.teamId || ""} corpId=${doc.corpId || ""}`,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[summary] scanned=${scanned} matchedDocs=${matchedDocs} replacedUrls=${replacedUrls} mode=${opts.dryRun ? "dry-run" : "apply"}`
|
||||
`[step] collection=${opts.dbName}.${opts.staffCollection} corpId=${opts.corpId || "全部"} mode=${opts.dryRun ? "dry-run" : "apply"}`
|
||||
);
|
||||
const staffStats = await processCollectionDocs({
|
||||
collection: staffCol,
|
||||
filter,
|
||||
batchDocs: opts.batchDocs,
|
||||
sortById: opts.sortById,
|
||||
skipDocs: opts.skipDocs,
|
||||
limitDocs: opts.limitDocs,
|
||||
dryRun: opts.dryRun,
|
||||
updateDoc: (doc) =>
|
||||
updateStaffQrcodeDoc(doc, {
|
||||
oldPrefix: opts.oldPrefix,
|
||||
newPrefix: opts.newPrefix,
|
||||
}),
|
||||
buildUpdate: ({ nextArchiveLink }) => ({
|
||||
$set: { archiveLink: nextArchiveLink },
|
||||
}),
|
||||
describeDoc: (doc) =>
|
||||
`_id=${doc._id} qrcodeId=${doc.qrcodeId || ""} corpId=${doc.corpId || ""}`,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[summary] team: scanned=${teamStats.scanned} matchedDocs=${teamStats.matchedDocs} replacedUrls=${teamStats.replacedUrls} | staff-qrcode: scanned=${staffStats.scanned} matchedDocs=${staffStats.matchedDocs} replacedUrls=${staffStats.replacedUrls} mode=${opts.dryRun ? "dry-run" : "apply"}`
|
||||
);
|
||||
} finally {
|
||||
await client.close();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user