Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/generate test data #102

Merged
merged 6 commits into from
Nov 10, 2024
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,6 @@ dist
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
.pnp.*

scripts/data/*
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
50 changes: 50 additions & 0 deletions scripts/generate-users-data.js
Original file line number Diff line number Diff line change
@@ -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 = './scripts/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);
58 changes: 58 additions & 0 deletions scripts/generate-words-data.js
Original file line number Diff line number Diff line change
@@ -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 = './scripts/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);
26 changes: 13 additions & 13 deletions src/routes/word/word.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand All @@ -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();
Expand All @@ -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);