윤준석

Merge branch 'feature/220524_nodejs_orm_model' into 'main'

Feature/220524 nodejs orm model

# nodejs 서버 유저 및 키워드 database connection 및 모델 생성 및 쿼리 함수

## database connection

1. Sequelize ORM 사용하여 db connection

## Model

1. User model 생성
2. Keyword model 생성
3. User-Keyword many to many 관계 생성

## Query

- addKeyword
  - 키워드 추가 함수 `INPUT: {keyword, userId}`
  - 유저 id 기반으로 키워드 추가 및 연결 테이블 레코드 생성

- deleteKeyword
  - 키워드 삭제 함수 `INPUT: {userId, keyword}`
  - 유저 id 기반으로 연결 테이블 레코드 삭제

- getKeywordsByUserId
  - 유저가 등록한 키워드 조회 함수 `INPUT: {userId}`
  - 유저 id 기반으로 연결된 모든 키워드 조회

- getUsersByKeyword
  - 키워드를 등록환 유저 조회 함수 `INPUT: {keyword}`
  - 키워드 기반으로 연결된 모든 유저 조회

- getAllUsers
  - 등록된 모든 유저 조회 함수 `INPUT: {NONE}`

- getAllKeywords
  - 등록된 모든 키워드 조회 함수 `INPUT: {NONE}`

See merge request !17
1 +let database = module.exports = {};
2 +
3 +const db = require("../models")
4 +const User = db.user
5 +const Keyword = db.keyword
6 +const UserKeyword = db.userKeyword
7 +
8 +
9 +database.addKeyword = async function(keyword, userId) {
10 +
11 + const u = await User.findOrCreate({
12 + where: {
13 + userId: userId
14 + }
15 + })
16 +
17 + const k = await Keyword.findOrCreate({
18 + where: {
19 + keyword: keyword
20 + }
21 + })
22 +
23 + await UserKeyword.findOrCreate({
24 + where: {
25 + userId: u[0].id,
26 + keywordId: k[0].id
27 + }
28 + })
29 +}
30 +
31 +database.deleteKeyword = async function(userId, keyword) {
32 +
33 + const u = await User.findOrCreate({
34 + where: {
35 + userId: userId
36 + }
37 + })
38 +
39 + const k = await Keyword.findOrCreate({
40 + where: {
41 + keyword: keyword
42 + }
43 + })
44 +
45 + await UserKeyword.destroy({
46 + where: {
47 + userId: u[0].id,
48 + keywordId: k[0].id
49 + }
50 + })
51 +}
52 +
53 +database.getKeywordsByUserId = async function(userId) {
54 +
55 + const keywords = await Keyword.findAll({
56 + attributes: ['keyword'],
57 + where: {
58 + '$user.userId$': userId
59 + },
60 + include: [{
61 + attributes: [],
62 + model: User,
63 + as: 'user'
64 + }],
65 + raw: true
66 + })
67 +
68 + let result = []
69 + for (let i = 0; i < keywords.length; i++) {
70 + result.push(keywords[i].keyword)
71 + }
72 +
73 + return result
74 +}
75 +
76 +database.getUsersByKeyword = async function(keyword) {
77 +
78 + const users = await User.findAll({
79 + attributes: ['userId'],
80 + where: {
81 + '$keyword.keyword$': keyword
82 + },
83 + include: [{
84 + attributes: [],
85 + model: Keyword,
86 + as: 'keyword'
87 + }],
88 + raw: true
89 + })
90 +
91 + let result = []
92 + for (let i = 0; i < users.length; i++) {
93 + result.push(users[i].userId)
94 + }
95 +
96 + return result
97 +}
98 +
99 +database.getAllUsers = async function() {
100 +
101 + const users = await User.findAll({
102 + raw: true
103 + })
104 +
105 + let result = []
106 + for (let i = 0; i < users.length; i++) {
107 + result.push(users[i].userId)
108 + }
109 +
110 + return result
111 +}
112 +
113 +database.getAllKeywords = async function() {
114 +
115 + const keywords = await Keyword.findAll({
116 + raw: true
117 + })
118 +
119 + let result = []
120 + for (let i = 0; i< keywords.length; i++) {
121 + result.push(keywords[i].keyword)
122 + }
123 +
124 + console.log(result)
125 + return result
126 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -3,13 +3,35 @@ const line = require("@line/bot-sdk"); ...@@ -3,13 +3,35 @@ const line = require("@line/bot-sdk");
3 const setFlexMessage = require("./apis/setFlexMessage"); 3 const setFlexMessage = require("./apis/setFlexMessage");
4 const fs = require("fs"); 4 const fs = require("fs");
5 5
6 +const { sequelize } = require('./models')
7 +const database = require("./apis/database");
8 +
9 +// Initialize DB connection
10 +sequelize.sync({ force: false })
11 + .then(() => {
12 + console.log('database connection complete');
13 + database.addKeyword("rtx3060", "junseok")
14 + database.getKeywordsByUserId("junseok")
15 + database.deleteKeyword("phobyjun", "rtx3080")
16 + database.getAllUsers()
17 + database.getUsersByKeyword("rtx3060")
18 + database.getAllKeywords()
19 + })
20 + .catch((err) => {
21 + console.log('database connection failed');
22 + });
23 +
24 +// Load .env configuration
6 require("dotenv").config(); 25 require("dotenv").config();
7 const config = { 26 const config = {
8 channelAccessToken: process.env.channelAccessToken, 27 channelAccessToken: process.env.channelAccessToken,
9 channelSecret: process.env.channelSecret, 28 channelSecret: process.env.channelSecret,
10 }; 29 };
11 30
31 +// Express app server initialization
12 const app = express(); 32 const app = express();
33 +
34 +// Create post request handler for chatbot
13 app.post("/webhook", line.middleware(config), (req, res) => { 35 app.post("/webhook", line.middleware(config), (req, res) => {
14 Promise.all(req.body.events.map(handleEvent)).then((result) => 36 Promise.all(req.body.events.map(handleEvent)).then((result) =>
15 res.json(result) 37 res.json(result)
......
1 +{
2 + "development": {
3 + "username": "root",
4 + "password": "mamuri",
5 + "database": "mamuri_db",
6 + "host": "127.0.0.1",
7 + "dialect": "mysql"
8 + },
9 + "test": {
10 + "username": "root",
11 + "password": null,
12 + "database": "database_test",
13 + "host": "127.0.0.1",
14 + "dialect": "mysql"
15 + },
16 + "production": {
17 + "username": "root",
18 + "password": null,
19 + "database": "database_production",
20 + "host": "127.0.0.1",
21 + "dialect": "mysql"
22 + }
23 +}
1 +'use strict';
2 +
3 +const fs = require('fs');
4 +const path = require('path');
5 +const Sequelize = require('sequelize');
6 +const basename = path.basename(__filename);
7 +const env = process.env.NODE_ENV || 'development';
8 +const config = require(__dirname + '/../config/config.json')[env];
9 +const db = {};
10 +
11 +let sequelize;
12 +if (config.use_env_variable) {
13 + sequelize = new Sequelize(process.env[config.use_env_variable], config);
14 +} else {
15 + sequelize = new Sequelize(config.database, config.username, config.password, config);
16 +}
17 +
18 +fs
19 + .readdirSync(__dirname)
20 + .filter(file => {
21 + return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
22 + })
23 + .forEach(file => {
24 + const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
25 + db[model.name] = model;
26 + });
27 +
28 +Object.keys(db).forEach(modelName => {
29 + if (db[modelName].associate) {
30 + db[modelName].associate(db);
31 + }
32 +});
33 +
34 +db.sequelize = sequelize;
35 +db.Sequelize = Sequelize;
36 +
37 +db.user = require("./user")(sequelize, Sequelize);
38 +db.keyword = require("./keyword")(sequelize, Sequelize);
39 +db.userKeyword = sequelize.define('user_keywords');
40 +
41 +db.user.belongsToMany(db.keyword, {through: db.userKeyword, as: 'keyword'});
42 +db.keyword.belongsToMany(db.user, {through: db.userKeyword, as: 'user'});
43 +
44 +module.exports = db;
1 +module.exports = (sequelize, DataTypes) => {
2 +
3 + return sequelize.define("keyword", {
4 + id: {
5 + type: DataTypes.INTEGER,
6 + autoIncrement: true,
7 + primaryKey: true
8 + },
9 + keyword: {
10 + type: DataTypes.STRING,
11 + allowNull: false
12 + }
13 + })
14 +}
...\ No newline at end of file ...\ No newline at end of file
1 +module.exports = (sequelize, DataTypes) => {
2 +
3 + return sequelize.define("user", {
4 + id: {
5 + type: DataTypes.INTEGER,
6 + autoIncrement: true,
7 + primaryKey: true
8 + },
9 + userId: {
10 + type: DataTypes.STRING,
11 + allowNull: false
12 + }
13 + })
14 +}
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
18 "@line/bot-sdk": "^7.5.0", 18 "@line/bot-sdk": "^7.5.0",
19 "dotenv": "^16.0.1", 19 "dotenv": "^16.0.1",
20 "express": "^4.18.1", 20 "express": "^4.18.1",
21 - "nodemon": "^2.0.16" 21 + "mysql2": "^2.3.3",
22 + "nodemon": "^2.0.16",
23 + "sequelize": "^6.20.0"
22 } 24 }
23 } 25 }
......