KDT/TIL

10/17 TIL : MySQL ์ •๊ทœํ™”, Mbti-App์— MongoDB ์ ์šฉ

ebulsok 2022. 10. 17. 18:56

๐Ÿ”Ž ์ •๊ทœํ™”

  • DB ์„ค๊ณ„์— ์žˆ์–ด์„œ ์ค‘๋ณต์„ ์ตœ์†Œํ™” ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐํ™” ํ•˜๋Š” ๊ณผ์ •
  • ํฌ๊ณ  ์กฐ์งํ™” ๋˜์ง€ ์•Š์€ ํ…Œ์ด๋ธ”์„ ์ž‘๊ณ  ์ž˜ ์กฐ์งํ™” ๋œ ํ…Œ์ด๋ธ”๋กœ ๋ณ€๊ฒฝ
  • ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ๋ฐ ์‚ญ์ œ ์‹œ์— ์ด์ƒ ํ˜„์ƒ์„ ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿšฉ ์ œ1์ •๊ทœํ˜•(1NF): ํ•˜๋‚˜์˜ ์ปฌ๋Ÿผ์€ ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ์†์„ฑ๋งŒ์„ ๊ฐ€์ ธ์•ผ ํ•จ

 

๐Ÿšฉ ์ œ2์ •๊ทœํ˜•(2NF): ๋ชจ๋“  ์ปฌ๋Ÿผ์— ๋Œ€ํ•œ ๋ถ€๋ถ„ ์ข…์†์ด ์—†์–ด์•ผ ํ•จ

 

๐Ÿšฉ ์ œ3์ •๊ทœํ˜•(3NF): ์ดํ–‰ ์ข…์†์„ฑ(A=B, B=C์—ฌ์„œ A=C์ธ ๊ฒฝ์šฐ)์ด ์—†์–ด์•ผ ํ•จ

 

๐Ÿ”Ž Foreign Key(์™ธ๋ž˜ ํ‚ค)

  • ์ •๊ทœํ™”๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด ํ…Œ์ด๋ธ”์€ ์ตœ์†Œํ•œ์˜ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์ง€๊ฒŒ ๋จ
  • ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ๋“ค์ผ ๋•Œ์—๋Š” ํ•œ๊บผ๋ฒˆ์— ๋งŽ์€ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ํ…Œ์ด๋ธ”์„ JOIN ํ•ด์„œ ๊ฐ€์ง€๊ณ  ์™€์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ
  • JOIN์„ ํ†ตํ•ด ํ…Œ์ด๋ธ”์„ ํ•ฉ์น˜๋Š”๋ฐ, ์ด ๋•Œ ๊ธฐ์ค€์ด ๋˜๋Š” ๊ฐ’(์„œ๋กœ ๊ณต์œ ํ•˜๊ณ  ์žˆ๋Š” ๊ฐ’)์„ ์™ธ๋ž˜ ํ‚ค๋ผ๊ณ  ํ•จ

 

๐Ÿ”Ž InitialData ํ…Œ์ด๋ธ” ๊ตฌ์„ฑ

  • Question Table: ID_PK, QUESTION_TEXT
  • Answer Table: ID_PK, ANSWER_TEXT, RESULT, QUESTION_ID_FK
  • Explanation Table: ID_PK, MBTI_TYPE, EXPLANATION, IMG_SRC

 

๐Ÿšฉ Question Table ์ƒ์„ฑ

QUESTION_TEST๊ฐ€ ์•„๋‹ˆ๋ผ TEXT ์ž…๋‹ˆ๋‹ค..

 

๐Ÿšฉ Answer Table ์ƒ์„ฑ

* cascade: ์™ธ๋ž˜ํ‚ค๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜์—ˆ์„ ๋•Œ ๋”ฐ๋ผ๊ฐ€๋Š” ๊ฒƒ

 

๐Ÿšฉ Explanation Table ์ƒ์„ฑ

 

๐Ÿšฉ Question Table ๋ฐ์ดํ„ฐ ์‚ฝ์ž…

insert into MyDB.question (ID_PK, QUESTION_TEXT) values
    (0, 'ํ‡ด๊ทผ ์ง์ „์— ๋™๋ฃŒ๋กœ๋ถ€ํ„ฐ ๊ฐœ๋ฐœ์ž ๋ชจ์ž„์— ์ดˆ๋Œ€๋ฅผ ๋ฐ›์€ ๋‚˜!!\n\nํ‡ด๊ทผ ์‹œ๊ฐ„์— ๋‚˜๋Š”?'),
    (1, '์ƒˆ๋กœ์šด ์„œ๋น„์Šค ๊ฐœ๋ฐœ ์ค‘์—, ๋™๋ฃŒ๊ฐ€ ์ƒˆ๋กœ ๋‚˜์˜จ ์‹ ๊ธฐ์ˆ ์„ ์“ฐ๋Š”๊ฒŒ ๋” ํŽธํ• ๊ฑฐ๋ผ๊ณ  ์ถ”์ฒœ์„ ํ•ด์ค€๋‹ค!\n\n๋‚˜์˜ ์„ ํƒ์€!?'),
    (2, '์„œ๋น„์Šค ์ถœ์‹œ ์ดํ‹€ ์ „ ์•ผ๊ทผ ์‹œ๊ฐ„, ๊ฐ‘์ž๊ธฐ ๋™๋ฃŒ๊ฐ€ ์–ด!?๋ฅผ ์™ธ์ณค๋‹ค!\n\n๋‚˜์˜ ์„ ํƒ์€?'),
    (3, 'ํŒ€์žฅ๋‹˜์ด xx ์”จ ๊ทธ์ „์— ๋งํ•œ ๊ธฐ๋Šฅ ๋‚ด์ผ ์˜คํ›„๊นŒ์ง€ ์™„๋ฃŒ ๋ถ€ํƒํ•ด์š”๋ผ๊ณ  ๋งํ–ˆ๋‹ค!\n\n๋‚˜์˜ ์„ ํƒ์€?');

 

๐Ÿšฉ Answer Table ๋ฐ์ดํ„ฐ ์‚ฝ์ž…

insert into MyDB.answer (ANSWER_TEXT, RESULT, QUESTION_ID_FK) values
    ('๊ทธ๋Ÿฐ ๋ชจ์ž…์„ ์™œ ์ด์ œ์„œ์•ผ ์•Œ๋ ค ์ค€๊ฑฐ์•ผ! ๋‹น์žฅ ๋ชจ์ž„์œผ๋กœ ์ถœ๋ฐœํ•œ๋‹ค', 'E', 0),
    ('1๋…„ ์ „์— ์•Œ๋ ค์คฌ์–ด๋„ ์•ˆ๊ฐ”์„ ๊ฑด๋ฐ ๋ญ”... ๋” ๋น ๋ฅด๊ฒŒ ์ง‘์œผ๋กœ ๊ฐ„๋‹ค', 'I', 0),
    ('๋ญ”์†Œ๋ฆฌ์—ฌ, ๊ทธ๋ƒฅ ํ•˜๋˜ ๋Œ€๋กœ ๊ฐœ๋ฐœํ•˜๋ฉด ๋˜๋Š”๊ฑฐ์ง€! ๊ธฐ์กด ์ƒ๊ฐ๋Œ€๋กœ ๊ฐœ๋ฐœํ•œ๋‹ค', 'S', 1),
    ('์˜คํ˜ธ? ๊ทธ๋Ÿฐ๊ฒŒ ์žˆ์–ด? ์ผ๋‹จ ๊ตฌ๊ธ€์„ ์ฐพ์•„๋ณธ๋‹ค', 'N', 1),
    ('๋ฌด์Šจ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฑฐ์ง€? ์•„๋งˆ DB ๊ด€๋ จ ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹๊นŒ? ๋น ๋ฅด๊ฒŒ ๋™๋ฃŒ์˜ ์ž๋ฆฌ๋กœ ๋‹ฌ๋ ค๊ฐ„๋‹ค', 'T', 2),
    ('์•„... ๋‚ด์ผ๋„ ์•ผ๊ทผ ๊ฐ์ด๊ตฌ๋‚˜ ใ… ใ… ! ์ผ๋‹จ ๋™๋ฃŒ์˜ ์ž๋ฆฌ๋กœ ๊ฐ€ ๋ณธ๋‹ค', 'F', 2),
    ('์ผ๋‹จ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ ์™„๋ฃŒํ•˜๊ณ , ๋‚˜๋จธ์ง€ ์‹œ๊ฐ„์— ๋…ผ๋‹ค', 'J', 3),
    ('๊ทธ๊ฑฐ ๋‚ด์ผ ์•„์นจ์— ์™€์„œ ๊ฐœ๋ฐœํ•ด๋„ ์ถฉ๋ถ„ ํ•˜๊ฒ ๋Š”๋ฐ? ์ผ๋‹จ ๋…ผ๋‹ค', 'P', 3);

 

๐Ÿšฉ Explanation Table ๋ฐ์ดํ„ฐ ์‚ฝ์ž…

insert into MyDB.explanation (MBTI_TYPE, EXPLANATION, IMG_SRC) values
    ('ESTJ', '๋ฌด๋ฆฌํ•œ ๊ฐœ๋ฐœ ์ผ์ •๋งŒ ์•„๋‹ˆ๋ผ๋ฉด ์ผ์ •์„ ์ฒ ์ €ํ•˜๊ฒŒ ์ง€ํ‚ฌ ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/estj.jpg'),
    ('ISTJ', '์Šค์Šค๋กœ ํ•˜๊ณ ์‹ถ์€ ๋ถ„์•ผ๋ฅผ ๋๊นŒ์ง€ ํŒŒ๊ณ  ๋“ค์–ด์„œ ๋๋‚ด ์„ฑ๊ณต ์‹œํ‚ฌ ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/istj.jpg'),
    ('ENTJ', '๋ฏธ๋ž˜์˜ ๋Šฅ๋ ฅ ์ฉŒ๋Š” ๊ฐœ๋ฐœ ํŒ€์žฅ๋‹˜์œผ๋กœ ๊ฐœ๋ฐœํŒ€์„ ์ด๋Œ ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/entj.jpg'),
    ('INTJ', 'ํ˜ผ์ž์„œ ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค ํ•ด๋‚ด๋Š” ์›๋งจ ์บ๋ฆฌ์˜ ํ‘œ๋ณธ! ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/intj.jpg'),
    ('ESFJ', '๊ฐœ๋ฐœํŒ€์˜ ๋ถ„์œ„๊ธฐ ๋ฉ”์ด์ปค์ด์ž ์•„์ด๋””์–ด ๋ฑ…ํฌ๊ฐ€ ๋  ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/esfj.jpg'),
    ('ISFJ', '๊ฐœ๋ฐœํŒ€์˜ ๋งˆ๋” ํ…Œ๋ ˆ์‚ฌ, ๊ณ ๋ฏผ ์ƒ๋‹ด์†Œ ์—ญํ• ์„ ์ž์ฒ˜ํ•˜๋Š” ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/isfj.jpg'),
    ('ENFJ', '๋‹น์‹ ์ด ์žˆ๋Š” ํŒ€์€ ์–ธ์ œ๋‚˜ ์˜ฌ๋ฐ”๋ฅธ ๊ณณ์„ ํ–ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! ํŒ€์›์€ ๋ฌผ๋ก  ํŒ€์˜ ๋ฐฉํ–ฅ์„ ์ฑ™๊ธฐ๋Š” ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/enfj.jpg'),
    ('INFJ', '์˜ˆ๋ฆฌํ•œ ํ†ต์ฐฐ๋ ฅ์œผ๋กœ ๋ชจ๋“  ๊ฒƒ์„ ๋‚ด๋‹ค๋ณด๋ฉด์„œ ์™„๋ฒฝํ•˜๊ฒŒ ๊ฐœ๋ฐœ์„ ํ•  ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/infj.jpg'),
    ('ESTP', '์ฟจํ•˜๊ฒŒ ์ž์‹ ์ด ํ•  ๊ฒƒ์„ ํ•˜๋ฉด์„œ ๋…ผ๋ฆฌ์ ์ธ ๊ฐœ๋ฐœ์„ ํ•  ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/estp.jpg'),
    ('ISTP', '๋‹จ์‹œ๊ฐ„์—๋„ ํšจ์œจ์ ์œผ๋กœ ๊ฐœ๋ฐœํ•˜์—ฌ ๋ชจ๋“  ๊ฒƒ์„ ์™„์„ฑํ•  ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/istp.jpg'),
    ('ENTP', '์Šค์Šค๋กœ ํฅ๋ฏธ๋งŒ ์ƒ๊ธด๋‹ค๋ฉด ๋‹น์žฅ์— ํŽ˜์ด์Šค๋ถ๋„ ๋งŒ๋“ค์–ด ๋ฒ„๋ฆด ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/entp.jpg'),
    ('INTP', 'ํ™•์‹คํ•œ ์ฃผ๊ด€๊ณผ ๋›ฐ์–ด๋‚œ ์ง€๋Šฅ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋…ผ๋ฆฌ์  ๊ฐœ๋ฐœ์„ ํ•  ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/intp.jpg'),
    ('ESFP', '๊ฐœ๋ฐœํŒ€์˜ ์—๋„ˆ์ž์ด์ €! ๊ฐœ๋ฐœํŒ€ ํŠน์œ ์˜ ์„œ๋จนํ•จ์„ ๊นจ๋Š” ๋‹น์‹ ! ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/esfp.jpg'),
    ('ISFP', '๋›ฐ์–ด๋‚œ ํ˜ธ๊ธฐ์‹ฌ๊ณผ ์˜ˆ์ˆ ์  ๊ฐ๊ฐ์œผ๋กœ ๊ฐœ๋ฐœํŒ€์˜ ๋ถ€์กฑํ•จ์„ ์ฑ„์›Œ๊ฐˆ ๋‹น์‹ ! ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/isfp.jpg'),
    ('ENFP', '์ž์œ ๋กœ์šด ์˜ํ˜ผ์œผ๋กœ ๊ฐœ๋ฐœํŒ€์˜ ์œคํ™œ์œ  ๋ฐ ํ™œ๋ ฅ์†Œ๊ฐ€ ๋˜์–ด์ค„ ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/enfp.jpg'),
    ('INFP', '๊ฐœ๋ฐœํŒ€์˜ ๊ทธ ์–ด๋–ค ํŠธ๋Ÿฌ๋ธ”๋„ ๋‹น์‹  ์•ž์—์„œ๋Š” ์‚ฌ๋ฅด๋ฅด ๋…น์„๋ฟ, ํŒ€์˜ ๊ทผ๊ฐ„์„ ๋‹ค์ ธ์ฃผ๋Š” ๋‹น์‹ ์˜ MBTI ๋Š”!', '/images/infp.jpg');

 

๐Ÿ”Ž Redux InitialData๋ฅผ SQL DB๋กœ๋ถ€ํ„ฐ ๋ฐ›๊ธฐ

๐Ÿšฉ survey, explanation ์ปจํŠธ๋กค๋Ÿฌ ์ถ”๊ฐ€

  • ํ˜„์žฌ MySQL์— ๋ฐ์ดํ„ฐ๋Š” ์ •๊ทœํ™”๋ฅผ ์œ„ํ•ด์„œ ํ…Œ์ด๋ธ”์ด ๋ถ„๋ฆฌ๋œ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— Question Table๊ณผ Answer Table์„ ๋™์‹œ์— ๊ฐ€์ง€๊ณ  ์™€์•ผ ํ•จ
  • ๊ธฐ์กด controller ๋ชจ๋“ˆ์— getSurvey, getExplanation ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , JOIN์œผ๋กœ ํ•ฉ์นœ ๋ฐ์ดํ„ฐ์˜ ๊ฐ’ ์ „๋‹ฌ
// data-server/controllers/dataController.js
    getSurvey: (cb) => {
        connection.query(
          'SELECT * FROM MyDB.question q LEFT JOIN MyDB.answer a ON q.ID_PK=a.QUESTION_ID_FK',
          (err, data) => {
            if(err) throw err;
            cb(data);
          }
        );
    },
    getExplanation: (cb) => {
        connection.query('SELECT * FROM MyDB.explanation', (err, data) => {
          if (err) throw err;
          cb(data);
        });
    },

 

๐Ÿšฉ survey, explanation router ์„ค์ •

// data-server/routes/data.js
    router.get('/survey', (req, res) => {
      db.getSurvey((data) => {
        console(data);
        res.send(data);
      });
    });
    
    router.get('/explanation', (req, res) => {
        db.getExplanation((data) => {
        console.log(data);
        res.send(data);
        });
    });

 

๐Ÿšฉ React์—์„œ ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ

// src/components/Start.js
useEffect(() => {
    async function fetchData() {
      const resCount = await fetch('http://localhost:4000/data/count');
      if (resCount.status === 200) {
        const num = await resCount.json();
        if (num[0].counts !== 0) setCounts(num[0].counts);
      } else throw new Error('ํ†ต์‹  ์ด์ƒ');

      //survey ๊ฐ’์„ ์œ„ํ•œ JOIN Table์˜ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ
      const resSurvey = await fetch('http://localhost:4000/data/survey');
      if (resSurvey.status === 200) {
        const surveyData = await resSurvey.json();

        // explanation table์˜ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ
        const resExplanation = await fetch('http://localhost:4000/data/explanation');
        if(resExplanation.status === 200) {
          const explanationData = await resExplanation.json();
          console.log(explanationData);
        } else throw new Error('ํ†ต์‹  ์ด์ƒ');
      } else throw new Error('ํ†ต์‹  ์ด์ƒ');
    }
    fetchData();
}, [counts]);

 

๐Ÿšฉ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ ๊พธ๋ฏธ๊ธฐ

  • DB์—์„œ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋Š” redux์—์„œ ์„ธํŒ…ํ–ˆ๋˜ initialState์™€ ๊ตฌ์กฐ๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๊ณต์ด ํ•„์š”ํ•จ
// src/components/Start.js
function makeData(survey, explanation) {
  const initData = { survey: [], explanation: {} };
  if(initData.survey.length === 0) {
    for(let i = 0; i < survey.length; i = i + 2) {
      initData.survey.push({
        question: survey[i].QUESTION_TEXT,
        answer: [
          {
            text: survey[i].ANSWER_TEXT,
            result: survey[i].RESULT,
          },
          {
            text: survey[i + 1].ANSWER_TEXT,
            result: survey[i + 1].RESULT,
          },
        ],
      });
    }

    for(let i = 0; i< explanation.length; i++) {
      initData.explanation[explanation[i].MBTI_TYPE] = {
        explanation: explanation[i].EXPLANATION,
        img: explanation[i].IMG_SRC,
      };
    }
  }
  return initData;
}

 

๐Ÿšฉ redux ์ˆ˜์ •ํ•˜๊ธฐ

  • ๊ฐ€๊ณตํ•œ ๋ฐ์ดํ„ฐ๋ฅผ redux์— ์ „๋‹ฌํ•˜์—ฌ ์ดˆ๊ธฐ ๊ฐ’์œผ๋กœ ๋งŒ๋“ค๊ธฐ
  • ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๋Š” ์ž‘์—…๋„ ํ•˜๋‚˜์˜ action์ด๋ฏ€๋กœ redux์— action type ์„ค์ •, ์ƒ์„ฑ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ, reducer ์ž‘์—…ํ•˜๊ธฐ
// src/store/modules/mbti.js
// ๋ฆฌ์•กํŠธ ์•ฑ ์ตœ์ดˆ ์‹คํ–‰ ์‹œ reducer์— ์ „๋‹ฌํ•  ๋นˆ ์ดˆ๊ธฐ ๊ฐ’
const initStateEmpty = {
  mbtiResult: '',
  page: 0,
  survey: [],
  explanation: {},
}

// ์•ก์…˜ ํƒ€์ž…(๋ฌธ์ž์—ด)
const INIT = 'mbti/INIT';
const CHECK = 'mbti/CHECK';
const NEXT = 'mbti/NEXT';
const RESET = 'mbti/RESET';

// ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜
export function init(data) {
  return {
    type: INIT,
    payload: data,
  }
}
// ...

// reducer
export default function mbti(state = initStateEmpty, action) {
  switch (action.type) {
    case INIT:
      return {
        ...state,
        survey: action.payload.survey,
        explanation: action.payload.explanation,
      };
// ...

 

๐Ÿšฉ ๋งŒ๋“ค์–ด์ง„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๊ธฐ

  • dispatch๋ฅผ ํ†ตํ•ด init() ํ•จ์ˆ˜์— ๋‹ด์•„์„œ ์ „๋‹ฌ
// src/components/Start.js
    useEffect(() => {
        async function fetchData() {
          const resCount = await fetch('http://localhost:4000/data/count');
          if (resCount.status === 200) {
            const num = await resCount.json();
            if (num[0].counts !== 0) setCounts(num[0].counts);
          } else throw new Error('ํ†ต์‹  ์ด์ƒ');

          //survey ๊ฐ’์„ ์œ„ํ•œ JOIN Table์˜ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ
          const resSurvey = await fetch('http://localhost:4000/data/survey');
          if (resSurvey.status === 200) {
            const surveyData = await resSurvey.json();

            // explanation table์˜ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ
            const resExplanation = await fetch(
              'http://localhost:4000/data/explanation'
            );
            if (resExplanation.status === 200) {
              const explanationData = await resExplanation.json();
              const madeData = makeData(surveyData, explanationData);
              dispatch(init(madeData));
            } else throw new Error('ํ†ต์‹  ์ด์ƒ');
          } else throw new Error('ํ†ต์‹  ์ด์ƒ');
        }
        fetchData();
    }, [counts]);

๐Ÿ”Ž MongoDB๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ

๐Ÿšฉ MongoDB ๋ชจ๋“ˆ ์„ค์น˜ ๋ฐ ์„ธํŒ…

  • [ํ„ฐ๋ฏธ๋„] npm i mongodb
// data-server/mongoConnect.js
const { MongoClient, ServerApiVersion } = require('mongodb');

const uri = process.env.MDB_URI;

const client = new MongoClient(uri, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  serverApi: ServerApiVersion.v1,
});

module.exports = client;

 

๐Ÿšฉ MongoDB controller ์ƒ์„ฑ

  • ์„ค๋ฌธ์šฉ ๋ฐ์ดํ„ฐ๋ฅผ DB์— ์ €์žฅ์‹œ์ผœ์ฃผ๋Š” controller๋ถ€ํ„ฐ ์ƒ์„ฑ
// data-server/controllers/mongoController.js
const mongoClient = require('../mongoConnect');
const _client = mongoClient.connect();

const initState = {
  mbtiResult: '',
  page: 0, // 0: ์ธํŠธ๋กœ ํŽ˜์ด์ง€, 1 ~ n: ์„ ํƒ ํŽ˜์ด์ง€, n+1: ๊ฒฐ๊ณผ ํŽ˜์ด์ง€
  survey: [
    {
      question:
        'ํ‡ด๊ทผ ์ง์ „์— ๋™๋ฃŒ๋กœ๋ถ€ํ„ฐ ๊ฐœ๋ฐœ์ž ๋ชจ์ž„์— ์ดˆ๋Œ€๋ฅผ ๋ฐ›์€ ๋‚˜!!\n\nํ‡ด๊ทผ ์‹œ๊ฐ„์— ๋‚˜๋Š”?',
      answer: [
        {
          text: '๊ทธ๋Ÿฐ ๋ชจ์ž„์„ ์™œ ์ด์ œ์„œ์•ผ ์•Œ๋ ค ์ค€๊ฑฐ์•ผ! ๋‹น์žฅ ๋ชจ์ž„์œผ๋กœ ์ถœ๋ฐœํ•œ๋‹ค',
          result: 'E',
        },
        {
          text: '1๋…„ ์ „์— ์•Œ๋ ค์คฌ์–ด๋„ ์•ˆ๊ฐ”์„ ๊ฑด๋ฐ ๋ญ”... ๋” ๋น ๋ฅด๊ฒŒ ์ง‘์œผ๋กœ ๊ฐ„๋‹ค',
          result: 'I',
        },
      ],
    },
    {
      question:
        '์ƒˆ๋กœ์šด ์„œ๋น„์Šค ๊ฐœ๋ฐœ ์ค‘์—, ๋™๋ฃŒ๊ฐ€ ์ƒˆ๋กœ ๋‚˜์˜จ ์‹ ๊ธฐ์ˆ ์„ ์“ฐ๋Š”๊ฒŒ ๋” ํŽธํ• ๊ฑฐ๋ผ๊ณ  ์ถ”์ฒœ์„ ํ•ด์ค€๋‹ค!\n\n๋‚˜์˜ ์„ ํƒ์€!?',
      answer: [
        {
          text: '๋ญ”์†Œ๋ฆฌ์—ฌ, ๊ทธ๋ƒฅ ํ•˜๋˜ ๋Œ€๋กœ ๊ฐœ๋ฐœํ•˜๋ฉด ๋˜๋Š”๊ฑฐ์ง€! ๊ธฐ์กด ์ƒ๊ฐ๋Œ€๋กœ ๊ฐœ๋ฐœํ•œ๋‹ค',
          result: 'S',
        },
        {
          text: '์˜คํ˜ธ? ๊ทธ๋Ÿฐ๊ฒŒ ์žˆ์–ด? ์ผ๋‹จ ๊ตฌ๊ธ€์„ ์ฐพ์•„๋ณธ๋‹ค',
          result: 'N',
        },
      ],
    },
    {
      question:
        '์„œ๋น„์Šค ์ถœ์‹œ ์ดํ‹€ ์ „ ์•ผ๊ทผ ์‹œ๊ฐ„, ๊ฐ‘์ž๊ธฐ ๋™๋ฃŒ๊ฐ€ ์–ด!?๋ฅผ ์™ธ์ณค๋‹ค!\n\n๋‚˜์˜ ์„ ํƒ์€?',
      answer: [
        {
          text: '๋ฌด์Šจ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฑฐ์ง€? ์•„๋งˆ DB ๊ด€๋ จ ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹๊นŒ? ๋น ๋ฅด๊ฒŒ ๋™๋ฃŒ์˜ ์ž๋ฆฌ๋กœ ๋‹ฌ๋ ค๊ฐ„๋‹ค',
          result: 'T',
        },
        {
          text: '์•„... ๋‚ด์ผ๋„ ์•ผ๊ทผ ๊ฐ์ด๊ตฌ๋‚˜ ใ… ใ… ! ์ผ๋‹จ ๋™๋ฃŒ์˜ ์ž๋ฆฌ๋กœ ๊ฐ€ ๋ณธ๋‹ค',
          result: 'F',
        },
      ],
    },
    {
      question:
        'ํŒ€์žฅ๋‹˜์ด xx ์”จ ๊ทธ์ „์— ๋งํ•œ ๊ธฐ๋Šฅ ๋‚ด์ผ ์˜คํ›„๊นŒ์ง€ ์™„๋ฃŒ ๋ถ€ํƒํ•ด์š”๋ผ๊ณ  ๋งํ–ˆ๋‹ค!\n\n๋‚˜์˜ ์„ ํƒ์€?',
      answer: [
        {
          text: '์ผ๋‹จ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ ์™„๋ฃŒํ•˜๊ณ , ๋‚˜๋จธ์ง€ ์‹œ๊ฐ„์— ๋…ผ๋‹ค',
          result: 'J',
        },
        {
          text: '๊ทธ๊ฑฐ ๋‚ด์ผ ์•„์นจ์— ์™€์„œ ๊ฐœ๋ฐœํ•ด๋„ ์ถฉ๋ถ„ ํ•˜๊ฒ ๋Š”๋ฐ? ์ผ๋‹จ ๋…ผ๋‹ค',
          result: 'P',
        },
      ],
    },
  ],

  explanation: {
    ESTJ: {
      text: '๋ฌด๋ฆฌํ•œ ๊ฐœ๋ฐœ ์ผ์ •๋งŒ ์•„๋‹ˆ๋ผ๋ฉด ์ผ์ •์„ ์ฒ ์ €ํ•˜๊ฒŒ ์ง€ํ‚ฌ ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/estj.jpg',
    },
    ISTJ: {
      text: '์Šค์Šค๋กœ ํ•˜๊ณ ์‹ถ์€ ๋ถ„์•ผ๋ฅผ ๋๊นŒ์ง€ ํŒŒ๊ณ  ๋“ค์–ด์„œ ๋๋‚ด ์„ฑ๊ณต ์‹œํ‚ฌ ๋‹น์‹ ์˜ MBTI ๋Š”!',
      img: '/images/istj.jpg',
    },
    ENTJ: {
      text: '๋ฏธ๋ž˜์˜ ๋Šฅ๋ ฅ ์ฉŒ๋Š” ๊ฐœ๋ฐœ ํŒ€์žฅ๋‹˜์œผ๋กœ ๊ฐœ๋ฐœํŒ€์„ ์ด๋Œ ๋‹น์‹ ์˜ MBTI ๋Š”!',
      img: '/images/entj.jpg',
    },
    INTJ: {
      text: 'ํ˜ผ์ž์„œ ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค ํ•ด๋‚ด๋Š” ์›๋งจ ์บ๋ฆฌ์˜ ํ‘œ๋ณธ! ๋‹น์‹ ์˜ MBTI ๋Š”!',
      img: '/images/intj.jpg',
    },
    ESFJ: {
      text: '๊ฐœ๋ฐœํŒ€์˜ ๋ถ„์œ„๊ธฐ ๋ฉ”์ด์ปค์ด์ž ์•„์ด๋””์–ด ๋ฑ…ํฌ๊ฐ€ ๋  ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/esfj.jpg',
    },
    ISFJ: {
      text: '๊ฐœ๋ฐœํŒ€์˜ ๋งˆ๋” ํ…Œ๋ ˆ์‚ฌ, ๊ณ ๋ฏผ ์ƒ๋‹ด์†Œ ์—ญํ• ์„ ์ž์ฒ˜ํ•˜๋Š” ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/isfj.jpg',
    },
    ENFJ: {
      text: '๋‹น์‹ ์ด ์žˆ๋Š” ํŒ€์€ ์–ธ์ œ๋‚˜ ์˜ฌ๋ฐ”๋ฅธ ๊ณณ์„ ํ–ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! ํŒ€์›์€ ๋ฌผ๋ก  ํŒ€์˜ ๋ฐฉํ–ฅ์„ ์ฑ™๊ธฐ๋Š” ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/enfj.jpg',
    },
    INFJ: {
      text: '์˜ˆ๋ฆฌํ•œ ํ†ต์ฐฐ๋ ฅ์œผ๋กœ ๋ชจ๋“  ๊ฒƒ์„ ๋‚ด๋‹ค๋ณด๋ฉด์„œ ์™„๋ฒฝํ•˜๊ฒŒ ๊ฐœ๋ฐœ์„ ํ•  ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/infj.jpg',
    },
    ESTP: {
      text: '์ฟจํ•˜๊ฒŒ ์ž์‹ ์ด ํ•  ๊ฒƒ์„ ํ•˜๋ฉด์„œ ๋…ผ๋ฆฌ์ ์ธ ๊ฐœ๋ฐœ์„ ํ•  ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/estp.jpg',
    },
    ISTP: {
      text: '๋‹จ์‹œ๊ฐ„์—๋„ ํšจ์œจ์ ์œผ๋กœ ๊ฐœ๋ฐœํ•˜์—ฌ ๋ชจ๋“  ๊ฒƒ์„ ์™„์„ฑํ•  ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/istp.jpg',
    },
    ENTP: {
      text: '์Šค์Šค๋กœ ํฅ๋ฏธ๋งŒ ์ƒ๊ธด๋‹ค๋ฉด ๋‹น์žฅ์— ํŽ˜์ด์Šค๋ถ๋„ ๋งŒ๋“ค์–ด ๋ฒ„๋ฆด ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/entp.jpg',
    },
    INTP: {
      text: 'ํ™•์‹คํ•œ ์ฃผ๊ด€๊ณผ ๋›ฐ์–ด๋‚œ ์ง€๋Šฅ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋…ผ๋ฆฌ์  ๊ฐœ๋ฐœ์„ ํ•  ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/intp.jpg',
    },
    ESFP: {
      text: '๊ฐœ๋ฐœํŒ€์˜ ์—๋„ˆ์ž์ด์ €! ๊ฐœ๋ฐœํŒ€ ํŠน์œ ์˜ ์„œ๋จนํ•จ์„ ๊นจ๋Š” ๋‹น์‹ ! ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/esfp.jpg',
    },
    ISFP: {
      text: '๋›ฐ์–ด๋‚œ ํ˜ธ๊ธฐ์‹ฌ๊ณผ ์˜ˆ์ˆ ์  ๊ฐ๊ฐ์œผ๋กœ ๊ฐœ๋ฐœํŒ€์˜ ๋ถ€์กฑํ•จ์„ ์ฑ„์›Œ๊ฐˆ ๋‹น์‹ ! ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/isfp.jpg',
    },
    ENFP: {
      text: '์ž์œ ๋กœ์šด ์˜ํ˜ผ์œผ๋กœ ๊ฐœ๋ฐœํŒ€์˜ ์œคํ™œ์œ  ๋ฐ ํ™œ๋ ฅ์†Œ๊ฐ€ ๋˜์–ด์ค„ ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/enfp.jpg',
    },
    INFP: {
      text: '๊ฐœ๋ฐœํŒ€์˜ ๊ทธ ์–ด๋–ค ํŠธ๋Ÿฌ๋ธ”๋„ ๋‹น์‹  ์•ž์—์„œ๋Š” ์‚ฌ๋ฅด๋ฅด ๋…น์„๋ฟ, ํŒ€์˜ ๊ทผ๊ฐ„์„ ๋‹ค์ ธ์ฃผ๋Š” ๋‹น์‹ ์˜ MBTI๋Š”!',
      img: '/images/infp.jpg',
    },
  },
};

const mongoDB = {
  setData: async () => {
    const client = await _client;
    const db = client.db('MBTI').collection('data');
    const result = await db.insertOne(initState);
    if (result.acknowledged) {
      return '์—…๋ฐ์ดํŠธ ์„ฑ๊ณต';
    } else throw new Error('ํ†ต์‹  ์ด์ƒ');
  },
};

module.exports = mongoDB;

 

๐Ÿšฉ MongoDB ์šฉ ๋ผ์šฐํ„ฐ ์„ค์ •

// data-server/routes/mongo.js
const express = require('express');
const router = express.Router();

const mongoDB = require('../controllers/mongoController');

router.post('/setdata', async (req, res) => {
  const msg = await mongoDB.setData();
  res.send(JSON.stringify(msg));
});

module.exports = router;
// data-server/server.js
const express = require('express');
const cors = require('cors');
const PORT = 4000;

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());

require('dotenv').config();

const dataRouter = require('./routes/data');
const mongoRouter = require('./routes/mongo');

app.use('/data', dataRouter);
app.use('/mongo', mongoRouter);

app.listen(PORT, () => {
  console.log(`๋ฐ์ดํ„ฐ ํ†ต์‹  ์„œ๋ฒ„๊ฐ€ ${PORT}์—์„œ ์ž‘๋™ ์ค‘`);
});

 

๐Ÿšฉ ์ปจํŠธ๋กค๋Ÿฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • ๋ฐฉ๋ฌธ์ž ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” getCounts
  • ๋ฐฉ๋ฌธ์ž ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” incCounts
  • ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” getData
// data-server/controllers/mongoController.js
    getCounts: async () => {
        const client = await _client;
        const db = client.db('MBTI').collection('counts');
        const data = await db.find({}).toArray();
        return data;
        },
        incCounts: async () => {
        const client = await _client;
        const db = client.db('MBTI').collection('counts');
        const result = await db.updateOne({ id: 1 }, { $inc: { counts: 1 } });
        if (result.acknowledged) {
          return '์—…๋ฐ์ดํŠธ ์„ฑ๊ณต';
        } else throw new Error('ํ†ต์‹  ์ด์ƒ');
        },
        getData: async () => {
        const client = await _client;
        const db = client.db('MBTI').collection('data');
        const data = await db.find({}).toArray();
        return data;
    },

 

๐Ÿšฉ mongoRouter ์„ค์ •

// data-server/routes/mongo.js
    router.get('/count', async (req, res) => {
      const counts = await mongoDB.getCounts();
      res.send(counts);
    });

    router.post('/inccount', async (req, res) => {
      const msg = await mongoDB.incCounts();
      res.send(JSON.stringify(msg));
    });

    router.get('/getdata', async (req, res) => {
      const data = await mongoDB.getData();
      res.send(data);
    });

 

๐Ÿšฉ MySQL ๋ฐ์ดํ„ฐ ๊ด€๋ จ ์ฝ”๋“œ ์ •๋ฆฌ

// src/components/Start.js
async function sqlFetchData() {
  const resCount = await fetch('http://localhost:4000/data/count');
  if (resCount.status === 200) {
    const num = await resCount.json();
    if (num[0].counts !== 0) setCounts(num[0].counts);
  } else throw new Error('ํ†ต์‹  ์ด์ƒ');

  //survey ๊ฐ’์„ ์œ„ํ•œ JOIN Table์˜ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ
  const resSurvey = await fetch('http://localhost:4000/data/survey');
  if (resSurvey.status === 200) {
    const surveyData = await resSurvey.json();

    // explanation table์˜ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ
    const resExplanation = await fetch(
      'http://localhost:4000/data/explanation'
    );
    if (resExplanation.status === 200) {
      const explanationData = await resExplanation.json();
      const madeData = makeData(surveyData, explanationData);
      dispatch(init(madeData));
    } else throw new Error('ํ†ต์‹  ์ด์ƒ');
  } else throw new Error('ํ†ต์‹  ์ด์ƒ');
}

async function mongoFetchData() {
  const resMongoCount = await fetch('http://localhost:4000/mongo/count');
  if (resMongoCount.status === 200) {
    const num = await resMongoCount.json();
    console.log(num);
  } else throw new Error('ํ†ต์‹  ์ด์ƒ');

  const resMongoData = await fetch('http://localhost:4000/mongo/getdata');
  if (resMongoData.status === 200) {
    const data = await resMongoData.json();
    console.log(data);
  } else throw new Error('ํ†ต์‹  ์ด์ƒ');
}

useEffect(() => {
    // sqlfetchData();
    mongoFetchData();
}, [counts]);
// src/components/Show.js
async function sqlSendData() {
    const resInc = await fetch('http://localhost:4000/data/inccount', {
      method: 'POST',
    });
    if (resInc.status === 200) console.log(await resInc.json());
    else throw new Error('ํ†ต์‹  ์ด์ƒ');
}

async function mongoSendData() {
    const resInc = await fetch('http://localhost:4000/mongo/inccount', {
      method: 'POST',
    });
    if (resInc.status === 200) console.log(await resInc.json());
    else throw new Error('ํ†ต์‹  ์ด์ƒ');
}

useEffect(() => {
    // sqlSendData();
    mongoSendData();
}, []);

 

๐Ÿšฉ counts ๊ฐ’ ์ „๋‹ฌ

  • Start ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐฉ๋ฌธ์ž ์ˆ˜ ๊ฐ’์„ update ํ•ด์ค˜์•ผ ํ•˜๋ฏ€๋กœ useState๋กœ ๊ฐ’์„ ์„ ์–ธํ•ด์„œ hook์— ์ „๋‹ฌ
// src/components/Start.js
    async function mongoFetchData() {
        const resMongoCount = await fetch('http://localhost:4000/mongo/count');
        if (resMongoCount.status === 200) {
        	const num = await resMongoCount.json();
        	if (num[0].counts !== 0) setCounts(num[0].counts);
        } else throw new Error('ํ†ต์‹  ์ด์ƒ');

        const resMongoData = await fetch('http://localhost:4000/mongo/getdata');
        if (resMongoData.status === 200) {
        	const data = await resMongoData.json();
        } else throw new Error('ํ†ต์‹  ์ด์ƒ');
    }

 

๐Ÿšฉ redux initialData ์ „๋‹ฌ

  • ์ด ๊ฐ’์€ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ผ์ด ์—†์œผ๋ฉฐ, Mbti ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋ฏ€๋กœ state๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Œ
  • init() ํ•จ์ˆ˜์— ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋งŒ ๋„ฃ์–ด์„œ dispatch๋กœ ์ „๋‹ฌ
// src/components/Start.js
    async function mongoFetchData() {
        const resMongoCount = await fetch('http://localhost:4000/mongo/count');
        if (resMongoCount.status === 200) {
        	const num = await resMongoCount.json();
        	if (num[0].counts !== 0) setCounts(num[0].counts);
        } else throw new Error('ํ†ต์‹  ์ด์ƒ');

        const resMongoData = await fetch('http://localhost:4000/mongo/getdata');
        if (resMongoData.status === 200) {
        	const data = await resMongoData.json();
        	if (data[0].survey.length !== 0) dispatch(init(data[0]));
        } else throw new Error('ํ†ต์‹  ์ด์ƒ');
    }

 

๐Ÿ“Œ ์ฝ”๋“œ: https://github.com/ebulsok/KDT-React-MBTI.git

'KDT > TIL' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

10/14 TIL : MySQL ์ ์šฉ  (0) 2022.10.17
10/12 TIL : React SPA ์ œ์ž‘(Mbti-app)  (0) 2022.10.17
10/7 TIL : Redux, ๊ฐ„๋‹จํ•œ Todo-list ๋งŒ๋“ค๊ธฐ  (0) 2022.10.14
10/5 TIL : React Router  (0) 2022.10.14
9/30 TIL : React Hooks(useEffect, useMemo)  (0) 2022.10.14