From 075e6d8c974993d92206423535bec312008bf7af Mon Sep 17 00:00:00 2001 From: jjikky Date: Sun, 3 Nov 2024 16:28:06 +0900 Subject: [PATCH 1/6] =?UTF-8?q?chore:=20gitignore=EC=97=90=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80=20#101?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3bfa646..0925b7f 100644 --- a/.gitignore +++ b/.gitignore @@ -131,4 +131,6 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +scripts/data/* \ No newline at end of file From 92abb828ce030005871fad8dd5871b8ecc72dd1e Mon Sep 17 00:00:00 2001 From: jjikky Date: Sun, 3 Nov 2024 16:34:48 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat=20:=20=EC=9C=A0=EC=A0=80=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=83=9D=EC=84=B1=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20#101?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/generate-users-data.js | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 scripts/generate-users-data.js diff --git a/scripts/generate-users-data.js b/scripts/generate-users-data.js new file mode 100644 index 0000000..5e0aafb --- /dev/null +++ b/scripts/generate-users-data.js @@ -0,0 +1,50 @@ +const fs = require('fs'); + +function generateRandomId() { + return Array(24) + .fill(0) + .map(() => Math.floor(Math.random() * 16).toString(16)) + .join(''); +} + +function generateRandomNickname(index) { + return `user${index}`; +} + +function generateUser(index) { + const now = new Date().toISOString(); + return { + _id: { $oid: generateRandomId() }, + deletedAt: null, + nickname: generateRandomNickname(index), + email: `user${index}@example.com`, + password: '$2b$10$NWhqlRrE5W0YMHlnaBi.CODbFjPZzvgT5G993eKoziVzrhH3M6KNC', + role: 'user', + snsId: null, + provider: null, + recentSearches: [], + requests: [], + createdAt: { $date: now }, + updatedAt: { $date: now }, + __v: 0, + }; +} + +function generateUsers(count) { + const users = []; + for (let i = 0; i < count; i++) { + users.push(generateUser(i)); + } + return users; +} + +async function generateAndSaveData(totalCount) { + const userData = generateUsers(totalCount); + const fileName = './data/test-users-data.json'; + fs.writeFileSync(fileName, JSON.stringify(userData, null, 2)); + + console.log('✅ 10000개의 유저 데이터가 생성되었습니다.'); + console.log('📁 파일 위치: users.json'); +} + +generateAndSaveData(10000).catch(console.error); From 51808ddc6db90333ee114fd394e6bd3e97baa15b Mon Sep 17 00:00:00 2001 From: jjikky Date: Sun, 3 Nov 2024 16:35:02 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat=20:=20=EB=8B=A8=EC=96=B4=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=83=9D=EC=84=B1=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20#101?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/generate-words-data.js | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 scripts/generate-words-data.js diff --git a/scripts/generate-words-data.js b/scripts/generate-words-data.js new file mode 100644 index 0000000..8294c28 --- /dev/null +++ b/scripts/generate-words-data.js @@ -0,0 +1,58 @@ +const fs = require('fs'); + +const prefixes = ['A', 'Ab', 'Ac', 'Ad', 'Af', 'Ag', 'Al', 'Am', 'An', 'Ap', 'Ar', 'As', 'At', 'Au']; +const middles = ['sync', 'pi', 'data', 'net', 'web', 'cloud', 'tech', 'dev', 'sys', 'log']; +const suffixes = ['Service', 'API', 'Hub', 'Lab', 'Flow', 'Base', 'Core', 'Plus', 'Pro', 'Box']; + +function generateRandomWord(index) { + const prefix = prefixes[Math.floor(Math.random() * prefixes.length)]; + const middle = middles[Math.floor(Math.random() * middles.length)]; + const suffix = suffixes[Math.floor(Math.random() * suffixes.length)]; + return `${prefix}${middle}${suffix}${index}`; +} + +function* generateWordBatch(totalCount, batchSize = 1000) { + for (let i = 0; i < totalCount; i += batchSize) { + const batch = []; + const currentBatchSize = Math.min(batchSize, totalCount - i); + + for (let j = 0; j < currentBatchSize; j++) { + const word = generateRandomWord(i + j); + batch.push({ + word, + awkPron: `어색한_${word}`, + comPron: `일반적인_${word}`, + info: `${word}에 대한 설명입니다. (테스트 데이터 ${i + j + 1})`, + suggestedBy: 'admin', + freq: Math.floor(Math.random() * 100), + }); + } + yield batch; + } +} + +async function generateAndSaveData(totalCount) { + console.time('Data Generation'); + const fileName = './data/test-words-data.json'; + const batchSize = 1000; + let currentBatch = 1; + const totalBatches = Math.ceil(totalCount / batchSize); + + fs.writeFileSync(fileName, '[\n', 'utf8'); + + for (const batch of generateWordBatch(totalCount, batchSize)) { + console.log(`처리 중: ${currentBatch}/${totalBatches} 배치`); + + const batchData = batch.map((item) => JSON.stringify(item)).join(',\n'); + fs.appendFileSync(fileName, currentBatch === 1 ? batchData : ',\n' + batchData, 'utf8'); + + currentBatch++; + } + + fs.appendFileSync(fileName, '\n]', 'utf8'); + + console.log(`✅ ${totalCount}개의 테스트 데이터 생성 완료!`); + console.log(`📁 파일 위치: ${fileName}`); +} + +generateAndSaveData(100000).catch(console.error); From 92b07d07094117b0a78e509f3f4b3a58d504664b Mon Sep 17 00:00:00 2001 From: jjikky Date: Sun, 3 Nov 2024 16:44:22 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=EC=A7=80=EC=A0=95?= =?UTF-8?q?=EB=90=9C=20=ED=8C=8C=EC=9D=BC=20=EC=A0=80=EC=9E=A5=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95=20#101?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/generate-users-data.js | 2 +- scripts/generate-words-data.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/generate-users-data.js b/scripts/generate-users-data.js index 5e0aafb..efe21d0 100644 --- a/scripts/generate-users-data.js +++ b/scripts/generate-users-data.js @@ -40,7 +40,7 @@ function generateUsers(count) { async function generateAndSaveData(totalCount) { const userData = generateUsers(totalCount); - const fileName = './data/test-users-data.json'; + const fileName = './scripts/data/test-users-data.json'; fs.writeFileSync(fileName, JSON.stringify(userData, null, 2)); console.log('✅ 10000개의 유저 데이터가 생성되었습니다.'); diff --git a/scripts/generate-words-data.js b/scripts/generate-words-data.js index 8294c28..87506be 100644 --- a/scripts/generate-words-data.js +++ b/scripts/generate-words-data.js @@ -33,7 +33,7 @@ function* generateWordBatch(totalCount, batchSize = 1000) { async function generateAndSaveData(totalCount) { console.time('Data Generation'); - const fileName = './data/test-words-data.json'; + const fileName = './scripts/data/test-words-data.json'; const batchSize = 1000; let currentBatch = 1; const totalBatches = Math.ceil(totalCount / batchSize); From 5ab0fe7b542535449a0323ce82233964950d366d Mon Sep 17 00:00:00 2001 From: jjikky Date: Sun, 3 Nov 2024 16:45:02 +0900 Subject: [PATCH 5/6] =?UTF-8?q?chore:=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=8C=8C=EC=9D=BC=20=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=B6=94=EA=B0=80=20#10?= =?UTF-8?q?1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b1bb55..f740488 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "lint": "eslint .", "lint:fix": "eslint . --fix", "format": "prettier --write .", - "prettier": "prettier --write --config ./.prettierrc './src/**'" + "prettier": "prettier --write --config ./.prettierrc './src/**'", + "generate:user": "node ./scripts/generate-users-data.js", + "generate:word": "node ./scripts/generate-words-data.js" }, "author": "", "license": "ISC", From f0611d32ffc0d432cc45d4a8a51b2678eede420d Mon Sep 17 00:00:00 2001 From: jjikky Date: Sun, 3 Nov 2024 16:46:02 +0900 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20word=20model=20=EC=9C=A0=EB=8B=88?= =?UTF-8?q?=ED=81=AC=20=ED=95=84=EB=93=9C=20=EA=B0=80=EB=8F=85=EC=84=B1=20?= =?UTF-8?q?=EC=9E=88=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/word/word.model.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/routes/word/word.model.js b/src/routes/word/word.model.js index f1e03d2..8a95bc0 100644 --- a/src/routes/word/word.model.js +++ b/src/routes/word/word.model.js @@ -3,7 +3,7 @@ const redisClient = require('../../common/modules/redis'); const wordSchema = new mongoose.Schema( { - word: { type: String, required: true, unique: true }, + word: { type: String, required: true }, awkPron: { type: String }, comPron: { type: String, required: true }, info: { type: String }, @@ -13,18 +13,7 @@ const wordSchema = new mongoose.Schema( { timestamps: true } ); -wordSchema.index({ word: 1 }); - -wordSchema.post(/^findOne/, async function (doc) { - const word = typeof this.getQuery().word === 'string' ? this.getQuery().word : doc?.word; - if (!word) { - console.error('❌ Error: No valid word found for Redis update'); - return; - } - - await redisClient.sendCommand(['ZINCRBY', 'popular_words', '1', word]); - await redisClient.expire('popular_words', 7200); -}); +wordSchema.index({ word: 1 }, { unique: true }); wordSchema.pre(/^find|update|save|remove|delete|count/, function (next) { this._startTime = Date.now(); @@ -33,8 +22,19 @@ wordSchema.pre(/^find|update|save|remove|delete|count/, function (next) { wordSchema.post(/^find|update|save|remove|delete|count/, function (result, next) { const latency = Date.now() - this._startTime; + console.log(this.getQuery()); console.log(`[${this.mongooseCollection.modelName}] ${this.op} query - ${latency}ms`); next(); }); +wordSchema.post(/^findOne/, async function (doc) { + const word = typeof this.getQuery().word === 'string' ? this.getQuery().word : doc?.word; + if (!word) { + console.error('❌ Error: No valid word found for Redis update'); + return; + } + await redisClient.sendCommand(['ZINCRBY', 'popular_words', '1', word]); + await redisClient.expire('popular_words', 7200); +}); + module.exports = mongoose.model('Word', wordSchema);