This commit is contained in:
104
migration_scripts/add-status-etc-fields.js
Normal file
104
migration_scripts/add-status-etc-fields.js
Normal file
@@ -0,0 +1,104 @@
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
/**
|
||||
* Migration: Thêm trường `status` (INT, default 0) và `etc` (TEXT, default '')
|
||||
* cho cả bảng `vocab` và `sentences`.
|
||||
*
|
||||
* - status: dùng để confirm lại vocab/sentence (0 = chưa confirm, etc.)
|
||||
* - etc: thông tin bổ sung dạng chuỗi
|
||||
*/
|
||||
async function run() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Database connected\n');
|
||||
|
||||
const queryInterface = sequelize.getQueryInterface();
|
||||
|
||||
// ─── VOCAB ───────────────────────────────────────────
|
||||
console.log('📦 Đang migrate bảng VOCAB...');
|
||||
|
||||
// Kiểm tra & thêm status
|
||||
try {
|
||||
await queryInterface.addColumn('vocab', 'status', {
|
||||
type: sequelize.Sequelize.DataTypes.INTEGER,
|
||||
defaultValue: 0,
|
||||
allowNull: false,
|
||||
comment: 'Trạng thái confirm (0 = chưa confirm)'
|
||||
});
|
||||
console.log(' ✅ Đã thêm cột "status" vào bảng vocab');
|
||||
} catch (e) {
|
||||
if (e.message.includes('Duplicate') || e.message.includes('already exists') || e.original?.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log(' ⚠️ Cột "status" đã tồn tại trong bảng vocab, bỏ qua.');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Kiểm tra & thêm etc
|
||||
try {
|
||||
await queryInterface.addColumn('vocab', 'etc', {
|
||||
type: sequelize.Sequelize.DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
allowNull: true,
|
||||
comment: 'Thông tin bổ sung'
|
||||
});
|
||||
console.log(' ✅ Đã thêm cột "etc" vào bảng vocab');
|
||||
} catch (e) {
|
||||
if (e.message.includes('Duplicate') || e.message.includes('already exists') || e.original?.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log(' ⚠️ Cột "etc" đã tồn tại trong bảng vocab, bỏ qua.');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── SENTENCES ───────────────────────────────────────
|
||||
console.log('\n📦 Đang migrate bảng SENTENCES...');
|
||||
|
||||
// Kiểm tra & thêm status
|
||||
try {
|
||||
await queryInterface.addColumn('sentences', 'status', {
|
||||
type: sequelize.Sequelize.DataTypes.INTEGER,
|
||||
defaultValue: 0,
|
||||
allowNull: false,
|
||||
comment: 'Trạng thái confirm (0 = chưa confirm)'
|
||||
});
|
||||
console.log(' ✅ Đã thêm cột "status" vào bảng sentences');
|
||||
} catch (e) {
|
||||
if (e.message.includes('Duplicate') || e.message.includes('already exists') || e.original?.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log(' ⚠️ Cột "status" đã tồn tại trong bảng sentences, bỏ qua.');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Kiểm tra & thêm etc (sentences đã có etc trong model nhưng chưa chắc có trong DB)
|
||||
try {
|
||||
await queryInterface.addColumn('sentences', 'etc', {
|
||||
type: sequelize.Sequelize.DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
allowNull: true,
|
||||
comment: 'Thông tin bổ sung'
|
||||
});
|
||||
console.log(' ✅ Đã thêm cột "etc" vào bảng sentences');
|
||||
} catch (e) {
|
||||
if (e.message.includes('Duplicate') || e.message.includes('already exists') || e.original?.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log(' ⚠️ Cột "etc" đã tồn tại trong bảng sentences, bỏ qua.');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n─────────────────────────────────────');
|
||||
console.log('✅ Migration hoàn tất!');
|
||||
console.log(' - vocab: status (INT, default 0), etc (TEXT, default "")');
|
||||
console.log(' - sentences: status (INT, default 0), etc (TEXT, default "")');
|
||||
console.log('─────────────────────────────────────');
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
53
migration_scripts/check-null-ref-id.js
Normal file
53
migration_scripts/check-null-ref-id.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const { Context } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
async function checkNullRefId() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Kết nối database thành công.');
|
||||
|
||||
// Kiểm tra tất cả các bản ghi có reference_id là null hoặc chuỗi rỗng
|
||||
const nullRefCount = await Context.count({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ reference_id: null },
|
||||
{ reference_id: '' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const totalCount = await Context.count();
|
||||
|
||||
// Thêm thống kê theo status để dễ hình dung
|
||||
const statsByStatus = await Context.findAll({
|
||||
attributes: ['status', [sequelize.fn('COUNT', sequelize.col('uuid')), 'count']],
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ reference_id: null },
|
||||
{ reference_id: '' }
|
||||
]
|
||||
},
|
||||
group: ['status']
|
||||
});
|
||||
|
||||
console.log('\n--- KẾT QUẢ KIỂM TRA REFERENCE_ID ---');
|
||||
console.log(`📊 Tổng số bản ghi trong bảng: ${totalCount}`);
|
||||
console.log(`❌ Số bản ghi có reference_id bị NULL/Trống: ${nullRefCount}`);
|
||||
console.log(`📈 Tỷ lệ lỗi: ${((nullRefCount / totalCount) * 100).toFixed(2)}%`);
|
||||
|
||||
if (statsByStatus.length > 0) {
|
||||
console.log('\nPhân loại theo Status:');
|
||||
statsByStatus.forEach(stat => {
|
||||
console.log(` - Status ${stat.get('status')}: ${stat.get('count')} bản ghi`);
|
||||
});
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi khi kiểm tra:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
checkNullRefId();
|
||||
57
migration_scripts/fix-reference-ids.js
Normal file
57
migration_scripts/fix-reference-ids.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const { Context, Vocab, Sentences } = require('../models');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
async function fixReferenceIds() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Kết nối database thành công.');
|
||||
|
||||
// Chỉ kiểm tra các bản ghi status 5 (hoặc bạn có thể bỏ where để check tất cả)
|
||||
const contexts = await Context.findAll({
|
||||
where: { status: 5 }
|
||||
});
|
||||
|
||||
console.log(`🔍 Đang kiểm tra ${contexts.length} bản ghi Context để sửa Reference ID...`);
|
||||
|
||||
let fixedCount = 0;
|
||||
let verifiedCount = 0;
|
||||
|
||||
for (const ctx of contexts) {
|
||||
// 1. Thử tìm trong Vocab trước
|
||||
const vocab = await Vocab.findOne({ where: { text: ctx.title } });
|
||||
if (vocab) {
|
||||
if (ctx.reference_id !== vocab.vocab_id) {
|
||||
await ctx.update({ reference_id: vocab.vocab_id });
|
||||
fixedCount++;
|
||||
console.log(`✅ Fixed ID: '${ctx.title}' -> ${vocab.vocab_id} (Vocab)`);
|
||||
} else {
|
||||
verifiedCount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. Nếu không thấy trong Vocab, thử tìm trong Sentences bằng trường context
|
||||
const sentence = await Sentences.findOne({ where: { text: ctx.context } });
|
||||
if (sentence) {
|
||||
if (ctx.reference_id !== sentence.id) {
|
||||
await ctx.update({ reference_id: sentence.id });
|
||||
fixedCount++;
|
||||
console.log(`✅ Fixed ID: '${ctx.title}' -> ${sentence.id} (Sentence)`);
|
||||
} else {
|
||||
verifiedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n--- KẾT QUẢ SỬA LỖI ---');
|
||||
console.log(`✅ Đã sửa: ${fixedCount} bản ghi.`);
|
||||
console.log(`✔️ Đã chuẩn sẵn: ${verifiedCount} bản ghi.`);
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fixReferenceIds();
|
||||
34
migration_scripts/migrate-status-6-to-5.js
Normal file
34
migration_scripts/migrate-status-6-to-5.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const { Context } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
async function migrate() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Kết nối database thành công.');
|
||||
|
||||
const fromDate = new Date('2026-02-28T09:00:00Z');
|
||||
|
||||
console.log(`🔍 Tìm kiếm các context có status = 6 và update từ ${fromDate.toISOString()} trở đi...`);
|
||||
|
||||
const [affectedCount] = await Context.update(
|
||||
{ status: 5 },
|
||||
{
|
||||
where: {
|
||||
status: 6,
|
||||
updated_at: {
|
||||
[Op.gte]: fromDate
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`✅ Đã cập nhật thành công ${affectedCount} bản ghi từ status 6 sang status 5.`);
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi khi migration:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
migrate();
|
||||
BIN
migration_scripts/output.txt
Normal file
BIN
migration_scripts/output.txt
Normal file
Binary file not shown.
108
migration_scripts/sync-images-to-all.js
Normal file
108
migration_scripts/sync-images-to-all.js
Normal file
@@ -0,0 +1,108 @@
|
||||
const { Context, Vocab, Sentences } = require('../models');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
// --- helper: xác định slot image từ tên file/URL ---
|
||||
function resolveImageSlot(imageUrl) {
|
||||
if (!imageUrl) return null;
|
||||
const filename = imageUrl.split('/').pop().split('?')[0];
|
||||
const parts = filename.split('_');
|
||||
for (const part of parts) {
|
||||
const key = part.toLowerCase();
|
||||
if (key === 'square') return 'image_square';
|
||||
if (key === 'small') return 'image_small';
|
||||
if (key === 'normal') return 'image_normal';
|
||||
}
|
||||
// Nếu không tìm thấy trong underscore, thử tìm trong toàn bộ URL
|
||||
if (imageUrl.toLowerCase().includes('square')) return 'image_square';
|
||||
if (imageUrl.toLowerCase().includes('small')) return 'image_small';
|
||||
if (imageUrl.toLowerCase().includes('normal')) return 'image_normal';
|
||||
return null;
|
||||
}
|
||||
|
||||
async function syncImages() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Kết nối database thành công.');
|
||||
|
||||
const contexts = await Context.findAll({
|
||||
where: { status: 5 }
|
||||
});
|
||||
|
||||
console.log(`📦 Tìm thấy ${contexts.length} bản ghi Context ở status 5.`);
|
||||
|
||||
let vocabUpdated = 0;
|
||||
let sentencesUpdated = 0;
|
||||
let skipped = 0;
|
||||
|
||||
for (const ctx of contexts) {
|
||||
const imageUrl = ctx.image;
|
||||
const slot = resolveImageSlot(imageUrl);
|
||||
|
||||
if (!imageUrl || !slot) {
|
||||
console.warn(`⚠️ ID ${ctx.uuid}: Không xác định được ảnh hoặc slot (URL: ${imageUrl}). Bỏ qua.`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
let updated = false;
|
||||
|
||||
// Ưu tiên 1: Dùng reference_id
|
||||
if (ctx.reference_id) {
|
||||
// Thử tìm trong Vocab
|
||||
const vocab = await Vocab.findByPk(ctx.reference_id);
|
||||
if (vocab) {
|
||||
await vocab.update({ [slot]: [imageUrl] });
|
||||
vocabUpdated++;
|
||||
updated = true;
|
||||
} else {
|
||||
// Thử tìm trong Sentences
|
||||
const sentence = await Sentences.findByPk(ctx.reference_id);
|
||||
if (sentence) {
|
||||
await sentence.update({ [slot]: [imageUrl] });
|
||||
sentencesUpdated++;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ưu tiên 2: Nếu chưa update được (hoặc ko có ref_id), thử match theo text
|
||||
if (!updated) {
|
||||
// Thử khớp Vocab.text = Context.title
|
||||
const vocabByText = await Vocab.findOne({ where: { text: ctx.title } });
|
||||
if (vocabByText) {
|
||||
await vocabByText.update({ [slot]: [imageUrl] });
|
||||
vocabUpdated++;
|
||||
updated = true;
|
||||
} else if (ctx.context) {
|
||||
// Thử khớp Sentences.text = Context.context
|
||||
const sentenceByText = await Sentences.findOne({ where: { text: ctx.context } });
|
||||
if (sentenceByText) {
|
||||
await sentenceByText.update({ [slot]: [imageUrl] });
|
||||
sentencesUpdated++;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
await ctx.update({ status: 6 });
|
||||
} else {
|
||||
console.warn(`❌ ID ${ctx.uuid}: Không tìm thấy entity đích để cập nhật ảnh (Title: ${ctx.title}).`);
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n--- KẾT QUẢ ĐỒNG BỘ ẢNH ---');
|
||||
console.log(`✅ Cập nhật Vocab: ${vocabUpdated} bản ghi.`);
|
||||
console.log(`✅ Cập nhật Sentences: ${sentencesUpdated} bản ghi.`);
|
||||
console.log(`⚠️ Bỏ qua hoặc lỗi: ${skipped} bản ghi.`);
|
||||
console.log(`📊 Tổng xử lý: ${contexts.length}`);
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi khi đồng bộ:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
syncImages();
|
||||
67
migration_scripts/sync-ref-id-from-sentences.js
Normal file
67
migration_scripts/sync-ref-id-from-sentences.js
Normal file
@@ -0,0 +1,67 @@
|
||||
const { Context, Sentences } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
async function syncRefIdFromSentences() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Kết nối database thành công.');
|
||||
|
||||
// 1. Tìm các bản ghi status = 5 và reference_id đang null hoặc trống
|
||||
const contexts = await Context.findAll({
|
||||
where: {
|
||||
status: 5,
|
||||
[Op.or]: [
|
||||
{ reference_id: null },
|
||||
{ reference_id: '' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`📊 Tìm thấy ${contexts.length} bản ghi status = 5 thiếu reference_id.`);
|
||||
|
||||
let updatedCount = 0;
|
||||
let notFoundCount = 0;
|
||||
|
||||
for (const context of contexts) {
|
||||
// Tìm câu trong bảng Sentences có text khớp chính xác với title của Context
|
||||
const sentence = await Sentences.findOne({
|
||||
where: {
|
||||
text: context.title
|
||||
}
|
||||
});
|
||||
|
||||
if (sentence) {
|
||||
await context.update({ reference_id: sentence.id });
|
||||
updatedCount++;
|
||||
// console.log(`✅ ID ${context.uuid}: Đã khớp '${context.title}' -> Sentence ID ${sentence.id}`);
|
||||
} else {
|
||||
notFoundCount++;
|
||||
// console.log(`⚠️ ID ${context.uuid}: Không tìm thấy câu '${context.title}' trong bảng Sentences.`);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Kiểm tra lại số lượng còn sót sau khi update
|
||||
const remainingCount = await Context.count({
|
||||
where: {
|
||||
status: 5,
|
||||
[Op.or]: [
|
||||
{ reference_id: null },
|
||||
{ reference_id: '' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n--- KẾT QUẢ CẬP NHẬT REFERENCE_ID TỪ SENTENCES ---');
|
||||
console.log(`✅ Đã cập nhật thành công: ${updatedCount} bản ghi.`);
|
||||
console.log(`❌ Không tìm thấy Sentence khớp: ${notFoundCount} bản ghi.`);
|
||||
console.log(`📊 Tổng số bản ghi status 5 vẫn còn thiếu reference_id: ${remainingCount}`);
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi khi migration:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
syncRefIdFromSentences();
|
||||
67
migration_scripts/sync-ref-id-from-vocab.js
Normal file
67
migration_scripts/sync-ref-id-from-vocab.js
Normal file
@@ -0,0 +1,67 @@
|
||||
const { Context, Vocab } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
async function syncRefIdFromVocab() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Kết nối database thành công.');
|
||||
|
||||
// 1. Tìm các bản ghi status = 5 và reference_id đang null hoặc trống
|
||||
const contexts = await Context.findAll({
|
||||
where: {
|
||||
status: 5,
|
||||
[Op.or]: [
|
||||
{ reference_id: null },
|
||||
{ reference_id: '' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`📊 Tìm thấy ${contexts.length} bản ghi status = 5 thiếu reference_id.`);
|
||||
|
||||
let updatedCount = 0;
|
||||
let notFoundCount = 0;
|
||||
|
||||
for (const context of contexts) {
|
||||
// Tìm từ trong bảng Vocab có text khớp chính xác với title của Context
|
||||
const vocab = await Vocab.findOne({
|
||||
where: {
|
||||
text: context.title
|
||||
}
|
||||
});
|
||||
|
||||
if (vocab) {
|
||||
await context.update({ reference_id: vocab.vocab_id });
|
||||
updatedCount++;
|
||||
// console.log(`✅ ID ${context.uuid}: Đã khớp '${context.title}' -> Vocab ID ${vocab.vocab_id}`);
|
||||
} else {
|
||||
notFoundCount++;
|
||||
console.log(`⚠️ ID ${context.uuid}: Không tìm thấy từ '${context.title}' trong bảng Vocab.`);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Kiểm tra lại số lượng còn sót sau khi update
|
||||
const remainingCount = await Context.count({
|
||||
where: {
|
||||
status: 5,
|
||||
[Op.or]: [
|
||||
{ reference_id: null },
|
||||
{ reference_id: '' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n--- KẾT QUẢ CẬP NHẬT REFERENCE_ID ---');
|
||||
console.log(`✅ Đã cập nhật thành công: ${updatedCount} bản ghi.`);
|
||||
console.log(`❌ Không tìm thấy Vocab khớp: ${notFoundCount} bản ghi.`);
|
||||
console.log(`📊 Tổng số bản ghi status 5 vẫn còn thiếu reference_id: ${remainingCount}`);
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi khi migration:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
syncRefIdFromVocab();
|
||||
70
migration_scripts/update-type-image-from-url.js
Normal file
70
migration_scripts/update-type-image-from-url.js
Normal file
@@ -0,0 +1,70 @@
|
||||
const { Context } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
async function updateTypeImage() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ Kết nối database thành công.');
|
||||
|
||||
// 1. Tìm các bản ghi status = 5 và type_image đang null
|
||||
const contexts = await Context.findAll({
|
||||
where: {
|
||||
status: 5,
|
||||
[Op.or]: [
|
||||
{ type_image: null },
|
||||
{ type_image: '' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`📊 Tìm thấy ${contexts.length} bản ghi status = 5 thiếu type_image.`);
|
||||
|
||||
let updatedCount = 0;
|
||||
let skippedCount = 0;
|
||||
|
||||
for (const context of contexts) {
|
||||
if (!context.image) {
|
||||
skippedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Logic trích xuất type_image từ URL: https://image.senaai.tech/type/filename.jpg
|
||||
// Ví dụ: https://image.senaai.tech/square/cool_square_1772002797233.jpg -> type là 'square'
|
||||
const match = context.image.match(/image\.senaai\.tech\/([^/]+)\//);
|
||||
|
||||
if (match && match[1]) {
|
||||
const extractedType = match[1];
|
||||
await context.update({ type_image: extractedType });
|
||||
updatedCount++;
|
||||
console.log(`✅ ID ${context.id}: Cập nhật type_image = '${extractedType}' từ URL.`);
|
||||
} else {
|
||||
skippedCount++;
|
||||
console.log(`⚠️ ID ${context.id}: Không thể trích xuất type từ URL: ${context.image}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Kiểm tra xem còn sót cái nào không
|
||||
const remainingCount = await Context.count({
|
||||
where: {
|
||||
status: 5,
|
||||
[Op.or]: [
|
||||
{ type_image: null },
|
||||
{ type_image: '' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n--- KẾT QUẢ ---');
|
||||
console.log(`✅ Đã cập nhật: ${updatedCount} bản ghi.`);
|
||||
console.log(`⏭️ Bỏ qua (không có ảnh hoặc URL không khớp): ${skippedCount} bản ghi.`);
|
||||
console.log(`❌ Số lượng còn sót lại vẫn thiếu type_image: ${remainingCount} bản ghi.`);
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Lỗi khi cập nhật:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
updateTypeImage();
|
||||
Reference in New Issue
Block a user