<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>화이팅</title>
    <link>https://ginghambagle.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 28 Jul 2026 16:23:19 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>이라후</managingEditor>
    <item>
      <title>AWS Certified Data Engineer &amp;ndash; Associate (DEA-C01) 만점 합격 후기</title>
      <link>https://ginghambagle.tistory.com/169</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pRCrM/btsMfedWN1D/Jc3yG73Ak9e8RnxNMqzzXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pRCrM/btsMfedWN1D/Jc3yG73Ak9e8RnxNMqzzXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pRCrM/btsMfedWN1D/Jc3yG73Ak9e8RnxNMqzzXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpRCrM%2FbtsMfedWN1D%2FJc3yG73Ak9e8RnxNMqzzXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;423&quot; height=&quot;423&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;덤프 문제만 공부함. (총 205문제)&lt;/li&gt;
&lt;li&gt;총 준비기간은 2주 반&lt;/li&gt;
&lt;li&gt;(25년 2월 기준)실제 시험은 내 기억으로는 1문제가 처음 보는 문제였고&lt;/li&gt;
&lt;li&gt;나머지는 모두 덤프 문제와 똑같이 나왔고 대부분 보기의 순서까지 같았다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시험 접수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/certification/certified-data-engineer-associate/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AWS Certified Data Engineer &amp;ndash; Associate(DEA-C01)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크에서 시험에 대한 기본적인 정보를 확인하고 예약할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;AWS Certified Data Engineer - Associate(DEA-C01)은(는) 100~1,000의 점수로 구분되어 평가됩니다. 시험 합격에 필요한 점수는 720입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;30분 추가시간 받기&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;영어 원어민이 아니라면 30분의 시간을 더 받을 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 130분 + 30분 =&amp;gt; 160분&lt;/li&gt;
&lt;li&gt;EXAM REGISTRATION -&amp;gt; Exam accommodations에서 신청&lt;/li&gt;
&lt;li&gt;접수 전 미리 신청해야함&lt;/li&gt;
&lt;li&gt;한국어 시험으로 선택해도 적용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBrrBy/btsMfDYMdl4/KsCICHKIEAvgs0GbpFSn2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBrrBy/btsMfDYMdl4/KsCICHKIEAvgs0GbpFSn2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBrrBy/btsMfDYMdl4/KsCICHKIEAvgs0GbpFSn2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBrrBy%2FbtsMfDYMdl4%2FKsCICHKIEAvgs0GbpFSn2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2466&quot; height=&quot;920&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;920&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시험 준비&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 준비용 자료로는 &lt;a href=&quot;https://www.udemy.com/course/aws-data-engineer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유데미 강의&lt;/a&gt;와 덤프 문제를 준비 했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 덤프 문제만 공부해서 합격했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.examtopics.com/exams/amazon/aws-certified-data-engineer-associate-dea-c01/view/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ExamTopics&lt;/a&gt;의 DEA 문제들을 한 파일로 정리해 둔 파일을 공유받아서 공부했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일에는 196번 문제까지 있었고 시험 시점에는 205번 문제까지 업데이트가 되어있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 문제는 &lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;examtopics dea-c01 question 200&lt;/b&gt;&lt;/span&gt; 형식으로 구글링 하면 해당 문제 확인이 가능하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;덤프 공부 방법&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;각 문제 의 정답과 해설 확인(ExamTopics의 Discussion이 도움됨)&lt;/li&gt;
&lt;li&gt;정리된 문제와 해설 공부(2-3회 반복)&lt;/li&gt;
&lt;li&gt;백지 상태에서 풀어보기&lt;/li&gt;
&lt;li&gt;3에서 틀리거나 모르는 문제만 다시 풀기&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmi: 1번이 조금 오래 걸리고 하루에 10문제밖에 보지 못한 날도 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;온라인 시험으로 접수했다가 시스템 문제가 있어서 오프라인으로 다시 접수하면서 1주일간 대기시간도 생겼는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 포함해서 시작일부터 시험일까지 2주 반정도 걸렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 잘 모르는 서비스도 많고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 있는 그대로 읽고 보기도 있는 그대로 읽으면서 공부해서 어렵고 시간이 오래 걸렸는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제별로 정리를 하고&amp;nbsp;계속 반복하면 키워드 기준으로 보기를 소거하거나 정답 키워드를 찾을 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시험 당일&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;온라인/오프라인 모두 예약한 시각에 맞춰서 시험이 시작되는 시스템이 아니고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감독관이 한명씩 확인을 한 후 개별적으로 시작, 본인의 시작시간 기준으로 종료시간이 정해지는 방식이었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;온라인&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;30분 전부터 시스템에 접속 후 여러가지 테스트 후에 감독관과 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감독관이 주변환경 체크를 다시 한번 하고 승인해주면 시험이 시작되는 시스템&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 마친후 감독관 연결 대기시간이 꽤 길었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 온라인 시험을 신청 했는데 시험날 시스템 문제가 있어서 두번 재시작 후 시험기회가 없어졌다ㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS와 시험 대행사인 Pearson VUE 측에 모두 메일을 보내서 2일 후 환불을 받고 오프라인으로 재접수 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.pearsonvue.com/us/en/aws/email.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pearson VUE 이메일 문의 링크&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS에서 먼저 답장이 왔는데 Pearson Vue에서 5일동안 연락이 없으면 본인들이 처리해주겠다는 내용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두군데 모두 문의를 해보는게 좋을 것 같다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;오프라인 (LEXIS&amp;nbsp;EXAM&amp;nbsp;CENTRE)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;들어가자마자 이름과 접수한 시험을 확인 하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대기실에 있다가 도착한 순서대로 한명씩 시험실로 안내되는 시스템&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 시험을 본 지인이 시험이 끝나면 바로 합/불 여부가 나온다고 했던 것 같은데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오프라인에서 봐서 그런지(?) 그 자리에서는 결과가 나오지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 후기들처럼 시험 끝난 후 5시간 정도 후에 Credly에서 먼저 합격여부를 알려주는 이메일이 왔고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS에서는 12시간정도 지나서 왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험에 합격하면 자격증 시험 50% 할인 바우처를 주는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자격증 계정에서 Benefits -&amp;gt; Certification benefits 에서 확인 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유효기간은 합격한 시험 만료일까지.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ocH39/btsMfi1Cyvd/8gTIIZFAmcraQYTB4boKek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ocH39/btsMfi1Cyvd/8gTIIZFAmcraQYTB4boKek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ocH39/btsMfi1Cyvd/8gTIIZFAmcraQYTB4boKek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FocH39%2FbtsMfi1Cyvd%2F8gTIIZFAmcraQYTB4boKek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2144&quot; height=&quot;834&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합격만 하면 되는 시험이지만 만점받아서 기분이 좋다^^!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 틀린 문제도 있는 것 같은데 채점에 들어가지 않는 문제에서 틀린 듯 하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 안내서 기준으로 시험범위에 해당하는 서비스의 10%도 사용해보지 못한 것 같은데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험준비하며 덤프 문제를 공부한 것 만으로도 다양한 서비스를 알게됐고 이미 사용해본 서비스도 더 깊게 이해하는 데 도움이 되었다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>aws</category>
      <category>데이터엔지니어</category>
      <category>벼락치기</category>
      <category>자격증</category>
      <category>합격</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/169</guid>
      <comments>https://ginghambagle.tistory.com/169#entry169comment</comments>
      <pubDate>Wed, 12 Feb 2025 17:41:54 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Elastic Beanstalk 에러: failed to create: [AWSEBInstanceLaunchWaitCondition].</title>
      <link>https://ginghambagle.tistory.com/163</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #000716; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Elastic Beanstalk 환경 생성 중 에러&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용은 아래와 같다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000716; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u85Mj/btsKgDSNrkk/NQakDnaq7qBQ3jrxTASfvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u85Mj/btsKgDSNrkk/NQakDnaq7qBQ3jrxTASfvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u85Mj/btsKgDSNrkk/NQakDnaq7qBQ3jrxTASfvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu85Mj%2FbtsKgDSNrkk%2FNQakDnaq7qBQ3jrxTASfvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1176&quot; height=&quot;360&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 링크에서 해결법을 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://repost.aws/questions/QUuSGs2tFHQkyoiESiyeHtnA/awsebinstancelaunchwaitcondition-error-on-deploying-java-app-on-elastic-beanstalk&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://repost.aws/questions/QUuSGs2tFHQkyoiESiyeHtnA/awsebinstancelaunchwaitcondition-error-on-deploying-java-app-on-elastic-beanstalk&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729611085062&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;AWSEBInstanceLaunchWaitCondition error on deploying Java app on Elastic Beanstalk&quot; data-og-description=&quot;Hello, I keep having issues when trying to deploy a simple Java (.war) application to Elastic Beankstalk. Basically, everyime I get these messages on the events tab: &amp;gt; Environment health has transi...&quot; data-og-host=&quot;repost.aws&quot; data-og-source-url=&quot;https://repost.aws/questions/QUuSGs2tFHQkyoiESiyeHtnA/awsebinstancelaunchwaitcondition-error-on-deploying-java-app-on-elastic-beanstalk&quot; data-og-url=&quot;https://repost.aws/questions/QUuSGs2tFHQkyoiESiyeHtnA/awsebinstancelaunchwaitcondition-error-on-deploying-java-app-on-elastic-beanstalk&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bZgvsb/hyXlUBbjFQ/eRXirYfvK3wvFHUjqeSKU1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://repost.aws/questions/QUuSGs2tFHQkyoiESiyeHtnA/awsebinstancelaunchwaitcondition-error-on-deploying-java-app-on-elastic-beanstalk&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://repost.aws/questions/QUuSGs2tFHQkyoiESiyeHtnA/awsebinstancelaunchwaitcondition-error-on-deploying-java-app-on-elastic-beanstalk&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bZgvsb/hyXlUBbjFQ/eRXirYfvK3wvFHUjqeSKU1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AWSEBInstanceLaunchWaitCondition error on deploying Java app on Elastic Beanstalk&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hello, I keep having issues when trying to deploy a simple Java (.war) application to Elastic Beankstalk. Basically, everyime I get these messages on the events tab: &amp;gt; Environment health has transi...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;repost.aws&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciAimv/btsKeUIrif0/XU3Bo8jMkSL4TBIeeKsIYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciAimv/btsKeUIrif0/XU3Bo8jMkSL4TBIeeKsIYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciAimv/btsKeUIrif0/XU3Bo8jMkSL4TBIeeKsIYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciAimv%2FbtsKeUIrif0%2FXU3Bo8jMkSL4TBIeeKsIYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1314&quot; height=&quot;588&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원인과 해결법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션이 비공개 서브넷에 배포된 것이 문제였습니다. 다음과 같이 해결했어요:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;EC2 &amp;gt; 인스턴스&lt;/b&gt;로 이동&lt;/li&gt;
&lt;li&gt;실행 중인 EC2 인스턴스를 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Instance summary&lt;/b&gt;에서 서브넷 ID를 열어 할당된 서브넷을 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서브넷 테이블&lt;/b&gt;이 VPC에서 열림&lt;/li&gt;
&lt;li&gt;서브넷 ID를 클릭&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Route table&lt;/b&gt;에서 라우트 테이블 ID 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작업(Actions) &amp;gt; 서브넷 연결 편집(Edit subnet associations)&lt;/b&gt; 선택&lt;/li&gt;
&lt;li&gt;이름에 rds-pvt 접두사가 없는 서브넷을 선택&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 0.0.0.0/0로 가는 추가 목적지가 있고, 타겟은 인터넷 게이트웨이로 설정되었습니다. 이 변경을 한 후에는 새로운 Elastic Beanstalk 인스턴스를 오류 없이 몇 분 만에 생성할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;서브넷 연결 편집&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2536&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwpzbM/btsKfqmHm8y/M4ahJeoATkEK9MCwmMrYaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwpzbM/btsKfqmHm8y/M4ahJeoATkEK9MCwmMrYaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwpzbM/btsKfqmHm8y/M4ahJeoATkEK9MCwmMrYaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwpzbM%2FbtsKfqmHm8y%2FM4ahJeoATkEK9MCwmMrYaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2536&quot; height=&quot;926&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2536&quot; data-origin-height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2564&quot; data-origin-height=&quot;1108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caRd3U/btsKeLyhsjm/en8tFeIexk8yZXn9L9AWi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caRd3U/btsKeLyhsjm/en8tFeIexk8yZXn9L9AWi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caRd3U/btsKeLyhsjm/en8tFeIexk8yZXn9L9AWi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaRd3U%2FbtsKeLyhsjm%2Fen8tFeIexk8yZXn9L9AWi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2564&quot; height=&quot;1108&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2564&quot; data-origin-height=&quot;1108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;환경 다시 빌드&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oXcov/btsKfcoDQjN/ZjyQas46j4eqt2C13hRxw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oXcov/btsKfcoDQjN/ZjyQas46j4eqt2C13hRxw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oXcov/btsKfcoDQjN/ZjyQas46j4eqt2C13hRxw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoXcov%2FbtsKfcoDQjN%2FZjyQas46j4eqt2C13hRxw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;760&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;760&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMVDjy/btsKgaDpZoY/E9jg14hzX0kkB7gYsoNou0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMVDjy/btsKgaDpZoY/E9jg14hzX0kkB7gYsoNou0/img.png&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;606&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 50.8618%; margin-right: 10px;&quot; data-widthpercent=&quot;51.46&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMVDjy/btsKgaDpZoY/E9jg14hzX0kkB7gYsoNou0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMVDjy%2FbtsKgaDpZoY%2FE9jg14hzX0kkB7gYsoNou0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1130&quot; height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxiyBQ/btsKgiahg9M/yOPx0TPtLBViMZIpNt8Ll0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxiyBQ/btsKgiahg9M/yOPx0TPtLBViMZIpNt8Ll0/img.png&quot; data-origin-width=&quot;1984&quot; data-origin-height=&quot;1128&quot; data-is-animation=&quot;false&quot; data-filename=&quot;edited_blob&quot; data-widthpercent=&quot;48.54&quot; style=&quot;width: 47.9754%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxiyBQ/btsKgiahg9M/yOPx0TPtLBViMZIpNt8Ll0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxiyBQ%2FbtsKgiahg9M%2FyOPx0TPtLBViMZIpNt8Ll0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1984&quot; height=&quot;1128&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그 밖에 찾아봤던 페이지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/troubleshooting-kb.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/troubleshooting-kb.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/vpc.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/vpc.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/163</guid>
      <comments>https://ginghambagle.tistory.com/163#entry163comment</comments>
      <pubDate>Wed, 23 Oct 2024 01:06:38 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Elastic Beanstalk 에러: The instance profile aws-elasticbeanstalk-ec2-role associated with the environment does not exist.</title>
      <link>https://ginghambagle.tistory.com/162</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/30790666/error-with-not-existing-instance-profile-while-trying-to-get-a-django-project-ru/76620598#76620598&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/30790666/error-with-not-existing-instance-profile-while-trying-to-get-a-django-project-ru/76620598#76620598&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729609200295&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Error with not existing instance profile while trying to get a django project running on AWS Beanstalk&quot; data-og-description=&quot;I&amp;#96;m trying to deploy a django project to AWS Beanstalk following this tutorial. I executed eb create and after a while I get the error The instance profile aws-elasticbeanstalk-ec2-role associa...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/30790666/error-with-not-existing-instance-profile-while-trying-to-get-a-django-project-ru/76620598#76620598&quot; data-og-url=&quot;https://stackoverflow.com/questions/30790666/error-with-not-existing-instance-profile-while-trying-to-get-a-django-project-ru&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/k2ZqN/hyXlWMynG1/h0YSs558IBlDmVOssjFL80/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/FlE4i/hyXlIALeIA/ZgD6kQi13yzZMLiGtf50NK/img.png?width=1913&amp;amp;height=809&amp;amp;face=0_0_1913_809,https://scrap.kakaocdn.net/dn/w9lSL/hyXlQFyrXB/CauuOToi6xPTS4mTKXYcwk/img.png?width=1430&amp;amp;height=681&amp;amp;face=0_0_1430_681&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/30790666/error-with-not-existing-instance-profile-while-trying-to-get-a-django-project-ru/76620598#76620598&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/30790666/error-with-not-existing-instance-profile-while-trying-to-get-a-django-project-ru/76620598#76620598&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/k2ZqN/hyXlWMynG1/h0YSs558IBlDmVOssjFL80/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/FlE4i/hyXlIALeIA/ZgD6kQi13yzZMLiGtf50NK/img.png?width=1913&amp;amp;height=809&amp;amp;face=0_0_1913_809,https://scrap.kakaocdn.net/dn/w9lSL/hyXlQFyrXB/CauuOToi6xPTS4mTKXYcwk/img.png?width=1430&amp;amp;height=681&amp;amp;face=0_0_1430_681');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Error with not existing instance profile while trying to get a django project running on AWS Beanstalk&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I`m trying to deploy a django project to AWS Beanstalk following this tutorial. I executed eb create and after a while I get the error The instance profile aws-elasticbeanstalk-ec2-role associa...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEx6Do/btsKfr6SAFt/nsq2K2xIqBsHS3v4qW5cV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEx6Do/btsKfr6SAFt/nsq2K2xIqBsHS3v4qW5cV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEx6Do/btsKfr6SAFt/nsq2K2xIqBsHS3v4qW5cV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEx6Do%2FbtsKfr6SAFt%2Fnsq2K2xIqBsHS3v4qW5cV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1092&quot; height=&quot;230&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 원인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 Elastic Beanstalk가 AWS 계정에서 처음으로 환경을 생성할 때 기본 EC2 인스턴스 프로파일인 aws-elasticbeanstalk-ec2-role을 자동으로 생성했습니다. 그러나 최근 AWS 보안 가이드라인에 따라 AWS 서비스가 다른 AWS 서비스(이 경우 EC2)와 신뢰 정책을 가진 역할을 자동으로 생성하는 것이 허용되지 않습니다. 문이 문제를 해결하기 위해서는 수동으로 인스턴스 프로파일을 생성해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인스턴스 프로파일 권한 정책 확인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경 생성 시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2단계 서비스 엑세스 구성 -&amp;gt; EC2 인스턴스 프로파일 -&amp;gt; 권한 세부 정보 보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2272&quot; data-origin-height=&quot;1364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pV13a/btsKfdntqiU/86QYfMzVGosMVOuWk0o7q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pV13a/btsKfdntqiU/86QYfMzVGosMVOuWk0o7q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pV13a/btsKfdntqiU/86QYfMzVGosMVOuWk0o7q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpV13a%2FbtsKfdntqiU%2F86QYfMzVGosMVOuWk0o7q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2272&quot; height=&quot;1364&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2272&quot; data-origin-height=&quot;1364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한 보기에서 어떻게 만들어야 하는지 확인 가능.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신뢰할 수 있는 엔터티: ec2.amazonaws.com&lt;/li&gt;
&lt;li&gt;권한: AWSElasticBeanstalkWebTier, AWSElasticBeanstalkWorkerTier, AWSElasticBeanstalkMulticontainerDocker&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1664&quot; data-origin-height=&quot;1518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FIdhN/btsKgBAEKfL/FxovzB77T8NhAOGwoawUM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FIdhN/btsKgBAEKfL/FxovzB77T8NhAOGwoawUM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FIdhN/btsKgBAEKfL/FxovzB77T8NhAOGwoawUM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFIdhN%2FbtsKgBAEKfL%2FFxovzB77T8NhAOGwoawUM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1664&quot; height=&quot;1518&quot; data-origin-width=&quot;1664&quot; data-origin-height=&quot;1518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;권한 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IAM -&amp;gt; 역할 -&amp;gt; 역할생성&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1단계 신뢰할 수 있는 엔터티 선택&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신뢰할 수 있는 엔터티 유형: AWS 서비스&lt;/li&gt;
&lt;li&gt;사용 사례: EC2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2206&quot; data-origin-height=&quot;1528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cApvvV/btsKfVmbzBt/pPAMQoTKkCm93WXRwLuAo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cApvvV/btsKfVmbzBt/pPAMQoTKkCm93WXRwLuAo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cApvvV/btsKfVmbzBt/pPAMQoTKkCm93WXRwLuAo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcApvvV%2FbtsKfVmbzBt%2FpPAMQoTKkCm93WXRwLuAo1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2206&quot; height=&quot;1528&quot; data-origin-width=&quot;2206&quot; data-origin-height=&quot;1528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2단계 권한 추가&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0c0d0e; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWSElasticBeanstalkWebTier&lt;/li&gt;
&lt;li&gt;AWSElasticBeanstalkWorkerTier&lt;/li&gt;
&lt;li&gt;AWSElasticBeanstalkMulticontainerDocker&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2438&quot; data-origin-height=&quot;1528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pDqPY/btsKe9L9sRo/9updR0ih1kgkVus5O9XJN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pDqPY/btsKe9L9sRo/9updR0ih1kgkVus5O9XJN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pDqPY/btsKe9L9sRo/9updR0ih1kgkVus5O9XJN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpDqPY%2FbtsKe9L9sRo%2F9updR0ih1kgkVus5O9XJN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2438&quot; height=&quot;1528&quot; data-origin-width=&quot;2438&quot; data-origin-height=&quot;1528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3단계 이름 지정, 검토 및 생성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;역할 이름: aws-elasticbeanstalk-ec2-role&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;1512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKexl1/btsKeEzlkfT/z5OKGHgeZO3pAHecy3gMLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKexl1/btsKeEzlkfT/z5OKGHgeZO3pAHecy3gMLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKexl1/btsKeEzlkfT/z5OKGHgeZO3pAHecy3gMLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKexl1%2FbtsKeEzlkfT%2Fz5OKGHgeZO3pAHecy3gMLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2464&quot; height=&quot;1512&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;1512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2438&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfgWby/btsKfcvjziM/I2Hfcwjv2TeysQ6igEf26k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfgWby/btsKfcvjziM/I2Hfcwjv2TeysQ6igEf26k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfgWby/btsKfcvjziM/I2Hfcwjv2TeysQ6igEf26k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfgWby%2FbtsKfcvjziM%2FI2Hfcwjv2TeysQ6igEf26k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2438&quot; height=&quot;1004&quot; data-origin-width=&quot;2438&quot; data-origin-height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;EB 환경 생성 시 적용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2단계 EC2 인스턴스 프로파일에서 방금 만든 프로파일 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2270&quot; data-origin-height=&quot;1352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JFjeW/btsKfVNekpQ/eDC9d37yfLnwaK6uhbHYak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JFjeW/btsKfVNekpQ/eDC9d37yfLnwaK6uhbHYak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JFjeW/btsKfVNekpQ/eDC9d37yfLnwaK6uhbHYak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJFjeW%2FbtsKfVNekpQ%2FeDC9d37yfLnwaK6uhbHYak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2270&quot; height=&quot;1352&quot; data-origin-width=&quot;2270&quot; data-origin-height=&quot;1352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/162</guid>
      <comments>https://ginghambagle.tistory.com/162#entry162comment</comments>
      <pubDate>Tue, 22 Oct 2024 23:57:14 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Elastic Beanstalk 에러: The following resource(s) failed to create: [AWSEBAutoScalingLaunchConfiguration].</title>
      <link>https://ginghambagle.tistory.com/161</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v5beA/btsKgCl0Gn4/yNKlyHO5eDnPMt5RUjfMs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v5beA/btsKgCl0Gn4/yNKlyHO5eDnPMt5RUjfMs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v5beA/btsKgCl0Gn4/yNKlyHO5eDnPMt5RUjfMs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv5beA%2FbtsKgCl0Gn4%2FyNKlyHO5eDnPMt5RUjfMs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1902&quot; height=&quot;210&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729603169882&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Launch Templates - AWS Elastic Beanstalk&quot; data-og-description=&quot;Once an environment is using launch templates, Elastic Beanstalk will never move it back to launch configurations. This is the case even if any these option settings that prompted the original use of launch templates are removed.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Launch Templates - AWS Elastic Beanstalk&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Once an environment is using launch templates, Elastic Beanstalk will never move it back to launch configurations. This is the case even if any these option settings that prompted the original use of launch templates are removed.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년 10월 1일부터 Amazon EC2 Auto Scaling 서비스는 새로운 계정에서 더 이상 런치 구성(Launch Configurations)을 생성하는 것을 지원하지 않습니다. 이 변경은 런치 구성이 단계적으로 폐지되고, EC2 Auto Scaling 서비스에서 런치 템플릿(Launch Templates)으로 대체되기 때문입니다. 자세한 내용은 Amazon EC2 Auto Scaling 사용자 가이드의 Auto Scaling 런치 구성(Launch Configurations)을 참조하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Elastic Beanstalk 계정 및 환경에 대한 런치 템플릿 전환의 영향은 다음과 같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기존 환경&lt;/b&gt;: 2024년 10월 1일 이전에 생성된 기존 환경은 영향을 받지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새로운 계정&lt;/b&gt;: 새로운 계정은 환경을 성공적으로 생성하기 위해 &lt;b&gt;런치 템플릿 옵션 설정&lt;/b&gt;에 나열된 옵션 중 적어도 하나를 일시적으로 설정해야 합니다. Auto Scaling 서비스는 새로운 계정에 대해서는 런치 템플릿을 사용하여 환경을 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기존 계정&lt;/b&gt;: 새로운 계정과 마찬가지로, 계정에 환경이 없는 특정 리전에서는 기존 계정도 동일한 절차를 따라야 합니다. 이 경우, 기존 계정은 주어진 리전에서 새 환경을 성공적으로 생성하려면 &lt;b&gt;런치 템플릿 옵션 설정&lt;/b&gt;에 나열된 옵션 중 적어도 하나를 일시적으로 설정해야 합니다. Auto Scaling 서비스는 주어진 리전의 해당 계정에 대해서만 런치 템플릿을 사용하여 환경을 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Elastic Beanstalk 환경을 새로 만들던 중 에러 발생.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;The&amp;nbsp;Launch&amp;nbsp;Configuration&amp;nbsp;creation&amp;nbsp;operation&amp;nbsp;is&amp;nbsp;not&amp;nbsp;available&amp;nbsp;in&amp;nbsp;your&amp;nbsp;account.&amp;nbsp;Use&amp;nbsp;launch&amp;nbsp;templates&amp;nbsp;to&amp;nbsp;create&amp;nbsp;configuration&amp;nbsp;templates&amp;nbsp;for&amp;nbsp;your&amp;nbsp;Auto&amp;nbsp;Scaling&amp;nbsp;groups.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;The following resource(s) failed to create: [AWSEBAutoScalingLaunchConfiguration]&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wjSek/btsKgBHrLP1/APd1AnJGNE30nqHrV7UO30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wjSek/btsKgBHrLP1/APd1AnJGNE30nqHrV7UO30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wjSek/btsKgBHrLP1/APd1AnJGNE30nqHrV7UO30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwjSek%2FbtsKgBHrLP1%2FAPd1AnJGNE30nqHrV7UO30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;814&quot; height=&quot;652&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 Launch Templates 안내 페이지를 읽어보다가 새로운 계정은 &lt;a href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-options&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;런치 템플릿 옵션 설정&lt;/a&gt; 의 옵션을 최소 하나 설정하라는 것을 발견. 새로운 계정은 Launch Configuration 이 아닌 Launch Template을 사용해서 환경을 생성하기 때문.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 환경 확인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-determine&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-determine&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729604735498&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Launch Templates - AWS Elastic Beanstalk&quot; data-og-description=&quot;Once an environment is using launch templates, Elastic Beanstalk will never move it back to launch configurations. This is the case even if any these option settings that prompted the original use of launch templates are removed.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-determine&quot; data-og-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-determine&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-determine&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-determine&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Launch Templates - AWS Elastic Beanstalk&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Once an environment is using launch templates, Elastic Beanstalk will never move it back to launch configurations. This is the case even if any these option settings that prompted the original use of launch templates are removed.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크에 나와있는대로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000716; text-align: left;&quot;&gt;AWS CloudFormation console -&amp;gt; 스택 -&amp;gt; 스택 세부 정보 -&amp;gt; 템플릿 탭&amp;nbsp;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000716; text-align: left;&quot;&gt;ctrl + f 로 launchtemplate&lt;span style=&quot;background-color: #ffffff; color: #000716; text-align: left;&quot;&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;launchconfiguration 를 검색해보면 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t1e4c/btsKf68YlD8/v5eskr7fSAhAoyu1SI99A1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t1e4c/btsKf68YlD8/v5eskr7fSAhAoyu1SI99A1/img.png&quot; data-alt=&quot;LaunchConfiguration으로 되어있음&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t1e4c/btsKf68YlD8/v5eskr7fSAhAoyu1SI99A1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft1e4c%2FbtsKf68YlD8%2Fv5eskr7fSAhAoyu1SI99A1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;841&quot; height=&quot;495&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;LaunchConfiguration으로 되어있음&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;런치 템플릿 옵션 설정 :&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-options&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-options&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729605165117&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Launch Templates - AWS Elastic Beanstalk&quot; data-og-description=&quot;Once an environment is using launch templates, Elastic Beanstalk will never move it back to launch configurations. This is the case even if any these option settings that prompted the original use of launch templates are removed.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-options&quot; data-og-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-options&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-options&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html#environments-cfg-autoscaling-launch-templates-options&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Launch Templates - AWS Elastic Beanstalk&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Once an environment is using launch templates, Elastic Beanstalk will never move it back to launch configurations. This is the case even if any these option settings that prompted the original use of launch templates are removed.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;RootVolumeType&lt;span&gt;&amp;nbsp;&lt;/span&gt;option set to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;gp3&lt;/b&gt;. You can set this option with the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.ec2.console.html&quot;&gt;console&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;or the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.ec2.namespace.html&quot;&gt;namespace&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;BlockDeviceMappings&lt;span&gt;&amp;nbsp;&lt;/span&gt;option contains&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;gp3&lt;/b&gt;. You can set this option with the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.ec2.console.html&quot;&gt;console&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;or the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.ec2.namespace.html&quot;&gt;namespace&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;DisableIMDSv1&lt;span&gt;&amp;nbsp;&lt;/span&gt;option set to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;true&lt;/b&gt;. We recommend that you set this option using the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.ec2.namespace.html&quot;&gt;namespace&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;EnableSpot&lt;span&gt;&amp;nbsp;&lt;/span&gt;option set to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;true&lt;/b&gt;. For more information, see&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-spot.html&quot;&gt;Spot instance support&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;and Configuration&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-configuration-approaches.html&quot;&gt;Auto Scaling group configuration&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1번 RootVolumeType gp3으로 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 1번 루트 볼륨을 gp3으로 설정해서 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경 생성 -&amp;gt; 4단계 (인스턴스 트래픽 및 크기 조정 구성)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;루트 볼륨(부팅 디바이스)&lt;/i&gt; 에서&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;루트 볼륨 유형&lt;/span&gt;&lt;/b&gt;을 &lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;범용 3(gp3)&lt;/span&gt;&lt;/b&gt;으로 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;1238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A4X4B/btsKguIpQLT/8qOCOi9WqWUYZo32bp8dEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A4X4B/btsKguIpQLT/8qOCOi9WqWUYZo32bp8dEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A4X4B/btsKguIpQLT/8qOCOi9WqWUYZo32bp8dEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA4X4B%2FbtsKguIpQLT%2F8qOCOi9WqWUYZo32bp8dEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1714&quot; height=&quot;1238&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;1238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #000000;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;s&gt;4번&lt;/s&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;IMDSv1은 기본이 비활성화 true인데 기본값으로 생성했을때 launch configuration으로 생성되었다. 그래서 namespace에서 설정하는 것을 권장하는 것 같은데..&lt;/s&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baG40s/btsKeO9sG8A/kIUsUHT8Erv70LOVvpmHhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baG40s/btsKeO9sG8A/kIUsUHT8Erv70LOVvpmHhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baG40s/btsKeO9sG8A/kIUsUHT8Erv70LOVvpmHhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaG40s%2FbtsKeO9sG8A%2FkIUsUHT8Erv70LOVvpmHhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;656&quot; height=&quot;200&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;환경 확인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000716; text-align: left;&quot;&gt;AWS CloudFormation console -&amp;gt; 스택 -&amp;gt; 스택 세부 정보 -&amp;gt; 템플릿 탭&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000716; text-align: left;&quot;&gt;이번에 생성된 스택 탬플릿을 보면 launch template를 사용해서 만들어진것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1924&quot; data-origin-height=&quot;1576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRoAOI/btsKgc2hBrt/N32vY4Gh25ZMOCsQdnR8Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRoAOI/btsKgc2hBrt/N32vY4Gh25ZMOCsQdnR8Pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRoAOI/btsKgc2hBrt/N32vY4Gh25ZMOCsQdnR8Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRoAOI%2FbtsKgc2hBrt%2FN32vY4Gh25ZMOCsQdnR8Pk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1924&quot; height=&quot;1576&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1924&quot; data-origin-height=&quot;1576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E9DNe/btsKgA2O570/VxrGGebFcvztGv3ZSOtDk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E9DNe/btsKgA2O570/VxrGGebFcvztGv3ZSOtDk0/img.png&quot; data-origin-width=&quot;1124&quot; data-origin-height=&quot;518&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 51.2564%; margin-right: 10px;&quot; data-widthpercent=&quot;51.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E9DNe/btsKgA2O570/VxrGGebFcvztGv3ZSOtDk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE9DNe%2FbtsKgA2O570%2FVxrGGebFcvztGv3ZSOtDk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1124&quot; height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EkZsc/btsKgf5GRsL/gL8U61DpRGd0EMxEO1k6a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EkZsc/btsKgf5GRsL/gL8U61DpRGd0EMxEO1k6a0/img.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;420&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.14&quot; data-filename=&quot;blob&quot; style=&quot;width: 47.5809%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EkZsc/btsKgf5GRsL/gL8U61DpRGd0EMxEO1k6a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEkZsc%2FbtsKgf5GRsL%2FgL8U61DpRGd0EMxEO1k6a0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;846&quot; height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 에러도 나지 않고 ec2 인스턴스도 잘 생성되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/161</guid>
      <comments>https://ginghambagle.tistory.com/161#entry161comment</comments>
      <pubDate>Tue, 22 Oct 2024 23:17:22 +0900</pubDate>
    </item>
    <item>
      <title>Django 모델에서 기본 키 참조: pk vs id</title>
      <link>https://ginghambagle.tistory.com/160</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Question.objects.get(pk=1000)과 Question.objects.get(id=1000)은 Django에서 동일한 결과를 반환한 다. 여기서 pk는 &quot;primary key&quot;의 약자로, Django 모델에서 기본 키를 참조하는 짧은 표현이다. 두 표현의 차이와 pk를 사용하는 이유는 다음과 같다:&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 명확성:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pk는 모델의 기본 키를 명시적으로 나타내므로, 모델의 기본 키가 무엇인지 확실히 알 수 있다.&lt;/li&gt;
&lt;li&gt;id를 사용할 경우, id가 기본 키임을 알고 있는 경우에만 이해할 수 있다. 다른 필드명이 기본 키인 경우, id를 사용하면 혼동할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 유연성:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모델에서 기본 키를 id가 아닌 다른 필드로 설정했을 때도 pk를 사용할 수 있다. 예를 들어, unique_id라는 필드를 기본 키로 설정하면 Question.objects.get(pk=1000)은 유효하지만 Question.objects.get(id=1000)은 오류를 발생시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 관습:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django의 많은 개발자들은 기본 키를 다룰 때 pk를 사용하여 코드를 일관되게 유지한다. (기본 키를 참조할 때의 일반적인 관습)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;둘 중 어떤 것을 써도 작동하지만, 일반적으로 &lt;b&gt;pk&lt;/b&gt;를 사용하는 것이 더 &lt;b&gt;명확&lt;/b&gt;하고 &lt;b&gt;유연&lt;/b&gt;하다. 기본 키를 나타낼 때 pk를 사용하는 것이 좋은 관행으로 여겨지므로, 가능하다면 pk를 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Django</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/160</guid>
      <comments>https://ginghambagle.tistory.com/160#entry160comment</comments>
      <pubDate>Thu, 10 Oct 2024 00:56:23 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 자료구조</title>
      <link>https://ginghambagle.tistory.com/159</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 리스트(list)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인덱스 접근 []&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;append()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pop() (맨 끝 요소 제거)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pop(i) (임의 위치 i에서 제거)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;insert(i, x)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;del del list[i]&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마지막 요소 제거: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;임의 위치에서 제거: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;remove(x)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&amp;nbsp;(값을 찾기 위한 선형 탐색 필요)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;index(x)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;sort()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(nlog⁡n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;reverse()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;len()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;슬라이싱 list[start:end]&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(k)&lt;/span&gt;&lt;/span&gt;&amp;nbsp;(슬라이싱되는 길이에 비례)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 딕셔너리(dict)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인덱스 접근 d[key]&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입 및 업데이트 d[key] = value&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 del d[key]&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;get(key)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pop(key)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;keys()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&amp;nbsp;(모든 키를 반환)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;values()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&amp;nbsp;(모든 값을 반환)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;items()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&amp;nbsp;(키-값 쌍을 반환)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;len()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 세트(set)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;삽입 s.add(x)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 s.remove(x)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탐색 x in s&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교집합 s1 &amp;amp; s2&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(min(len(s1),len(s2)))&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;합집합 s1 | s2&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(len(s1)+len(s2))&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;차집합 s1 - s2&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(len(s1))&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대칭차집합 s1 ^ s2&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(len(s1)+len(s2))&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 튜플(tuple)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인덱스 접근 t[i]&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;count(x)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;index(x)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;len()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;튜플은 불변(immutable) 자료구조로, 리스트와 유사하지만 요소를 변경할 수 없다는 점에서 리스트와 다르다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. deque (collections.deque)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;append() (끝에 요소 추가)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;appendleft() (앞에 요소 추가)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pop() (끝에서 요소 제거)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;popleft() (앞에서 요소 제거)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;extend(iterable)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(k)&lt;/span&gt;&lt;/span&gt;(길이에 비례)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;extendleft(iterable)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(k)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rotate(n)&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&amp;nbsp;(n번 회전)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;len()&lt;/b&gt;: &lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Python</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/159</guid>
      <comments>https://ginghambagle.tistory.com/159#entry159comment</comments>
      <pubDate>Tue, 8 Oct 2024 19:33:58 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 기능개발: math.ceil 대체 수식</title>
      <link>https://ginghambagle.tistory.com/158</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42586&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42586&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728106175656&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42586&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nStRJ/hyXazShqvJ/mklEI4ctczomN8kCuRmPv1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bc6EHb/hyXayePzPB/h2YP5l4MeHwPqxRiJ1AK8k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42586&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42586&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nStRJ/hyXazShqvJ/mklEI4ctczomN8kCuRmPv1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bc6EHb/hyXayePzPB/h2YP5l4MeHwPqxRiJ1AK8k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;풀이1&lt;/h3&gt;
&lt;pre id=&quot;code_1728106491439&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(progresses, speeds):
    answer = []
    days_left = [(100 - progresses[i] + speeds[i] -1) // speeds[i] for i in range(len(progresses))]
   
    day = days_left[0]
    cnt = 1
    
    for d in days_left[1:]: 
        if d &amp;lt;= day:
            cnt += 1
        else:
            answer.append(cnt)
            day = d
            cnt = 1
    
    answer.append(cnt)
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간복잡도는 days_left 구할때 O(n), for문에서 O(n)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; O(n)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;zip을 이용해서 progresses랑 speeds를 한번에 돌면서 하고싶었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게할지 모르겠음+문제 조건에서 리스트 길이가 100 이하래서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 새로운 리스트 days_left를 따로 만들어서 풀었다&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다른풀이1&lt;/h3&gt;
&lt;pre id=&quot;code_1728109767715&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from math import ceil

def solution(progresses, speeds):
    answer = []
    max_duration = ceil((100 - progresses[0]) / speeds[0])
    count = 0
    
    for progress, speed in zip(progresses, speeds):
        duration = ceil((100 - progress) / speed)
        # duration = -(-(100 - progress) // speed)
        if max_duration &amp;lt; duration:
            answer.append(count)
            count = 0
            max_duration = duration
        count += 1
    
    if count &amp;gt; 0:
        answer.append(count)
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 풀려던 의도대로 해결한 풀이법&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다른풀이2&lt;/h3&gt;
&lt;pre id=&quot;code_1728107486922&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(progresses, speeds):
    Q = []
    for p, s in zip(progresses, speeds):
        days_left = (100 - p + s - 1) // s  # 남은 일수 계산 (올림 효과)
        if not Q or Q[-1][0] &amp;lt; days_left:
            Q.append([days_left, 1])  # 새로운 배포 그룹 시작
        else:
            Q[-1][1] += 1  # 같은 배포 그룹에 포함
    return [q[1] for q in Q]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;zip() 이용한 풀이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원리스트 활용&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비교: 이전 코드와의 차이점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;첫 번째 코드 (기존 코드)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 작업이 완료될 일수를 계산한 후, 다시 한 번 순회하여 배포 가능한 작업들을 그룹화합니다.&lt;/li&gt;
&lt;li&gt;시간 복잡도는 &lt;b&gt;&lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;두 번째 코드 (새 코드)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;zip을 이용해 한 번의 순회만으로 남은 일수 계산과 그룹화를 동시에 처리합니다.&lt;/li&gt;
&lt;li&gt;시간 복잡도는 &lt;b&gt;&lt;span&gt;&lt;span&gt;O(n)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떤 코드가 더 나은가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가독성&lt;/b&gt;: 첫 번째 코드는 각 단계를 명확히 나눠서 처리합니다. 첫 번째 코드는 각 작업의 완료 일수를 먼저 계산하고, 그 이후에 배포 가능 여부를 판단하는 구조라서 이해하기 쉽습니다. 반면, 두 번째 코드는 한 번의 루프에서 모든 것을 처리하기 때문에 다소 복잡하게 느껴질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능&lt;/b&gt;: 두 코드는 모두 시간 복잡도가 &lt;span&gt;&lt;span&gt;&lt;b&gt;O(n)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;으로 동일하므로, 입력 크기 &lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;에 따른 성능 차이는 크지 않습니다. 하지만 두 번째 코드는 그룹화를 계산하는 과정을 반복해서 처리하지 않고, 한 번의 루프에서 모든 것을 해결하므로 &lt;b&gt;약간 더 효율적&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;첫 번째 코드&lt;/b&gt;는 가독성이 좋고, 직관적으로 단계별로 문제를 해결하는 방식입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;두 번째 코드&lt;/b&gt;는 한 번의 루프에서 작업을 처리하므로, &lt;b&gt;효율성이 조금 더 뛰어납니다&lt;/b&gt;. 단, 가독성 측면에서 약간 불리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;b&gt;두 번째 코드&lt;/b&gt;가 미세하게 더 효율적일 수 있지만, 코드의 명확성과 유지보수성을 고려하면 프로젝트 상황에 따라 두 코드 중 선택할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;math.ceil&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 math.ceil()함수를 사용해서 풀었는데 챗지피티가 다른 방법을 알려주었다&lt;/p&gt;
&lt;pre id=&quot;code_1728108014551&quot; class=&quot;vala&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# import math
# math.ceil((x - p) / s)

# 대신 아래 식으로 쓸 수 있다

(x - p + s - 1) // s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 호출 비용:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;math.ceil&lt;/span&gt;은 Python에서 함수를 호출하는 것이므로, 함수 호출에 대한 오버헤드가 발생합니다. 이 오버헤드는 특히 반복문 안에서 호출할 경우 성능에 영향을 미칠 수 있습니다.&lt;/li&gt;
&lt;li&gt;산술 연산: 반면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;(x - p + s - 1) // s&lt;/span&gt;는 단순한 산술 연산이므로, 계산이 더 빠르게 수행됩니다. 이 방식은 일반적으로 상수 시간&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;O(1)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;로 처리됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 -((p - 100) // s)로 푸는 방법도 있었는데 가독성과 미미한 성능의 차이에서 모두(x-p+s-1)//s가 낫다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/158</guid>
      <comments>https://ginghambagle.tistory.com/158#entry158comment</comments>
      <pubDate>Sat, 5 Oct 2024 15:05:00 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 예산: O(n^2) -&amp;gt; O(n log n)</title>
      <link>https://ginghambagle.tistory.com/157</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 링크&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12982&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12982&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728057974828&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12982&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dZzgb9/hyXd61YESF/74PqH2IwSJs4pabiukIKr0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/MwsfF/hyXaBo0q9f/vwQob0ktTZmMUAxikiIfw0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12982&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12982&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dZzgb9/hyXd61YESF/74PqH2IwSJs4pabiukIKr0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/MwsfF/hyXaBo0q9f/vwQob0ktTZmMUAxikiIfw0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;O(n^2)&lt;/h3&gt;
&lt;pre id=&quot;code_1728058009627&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(d, budget):
    d.sort() 
    while sum(d) &amp;gt; budget:
        d.pop()      
    return len(d)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sum()을 이용해 간단하게 푼 방법 but..&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. d.sort()&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 복잡도: O(n log n)&lt;/li&gt;
&lt;li&gt;sort()는 Timsort 알고리즘을 사용하므로 리스트 크기 n에 대해 &lt;b&gt;O(n log n)&lt;/b&gt;의 시간이 걸립니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. while sum(d) &amp;gt; budget:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sum(d)의 시간 복잡도는 리스트 내 모든 요소의 합을 구하는 작업으로, &lt;b&gt;O(n)&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;while 루프 내에서 sum(d)는 매번 반복되므로, 가장 나쁜 경우는 d의 모든 요소를 하나씩 제거하는 상황입니다. 즉, 루프는 최악의 경우 &lt;b&gt;n번 반복&lt;/b&gt;되며, 매번 &lt;b&gt;O(n)&lt;/b&gt;의 시간이 걸립니다. &lt;b&gt;-&amp;gt; O(n^2)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. d.pop()&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트의 마지막 요소를 제거하는 pop()은 &lt;b&gt;O(1)&lt;/b&gt;입니다. 따라서, 이 부분은 루프 내에서 시간 복잡도에 크게 영향을 미치지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;최종 시간 복잡도:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;O(n^2)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개선 방법&lt;/b&gt;: sum(d)를 루프 안에서 매번 계산하는 대신, budget에서 각 요소를 하나씩 빼나가면 시간 복잡도를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;O(n log n)&lt;/h3&gt;
&lt;pre id=&quot;code_1728058054854&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(d, budget): 
    d.sort()
    count = 0
    
    for cost in d:
        if budget - cost &amp;gt;= 0:
            budget -= cost
            count += 1
        else:
            break
            
    return count&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;개선된 로직의 시간 복잡도:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;d.sort(): &lt;b&gt;O(n log n)&lt;/b&gt; - 예산이 작은 부서부터 처리하기 위해 정렬.&lt;/li&gt;
&lt;li&gt;for 루프: &lt;b&gt;O(n)&lt;/b&gt; - 각 부서의 소요 비용을 하나씩 처리하면서 예산에서 차감.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;최종 시간 복잡도:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;O(n log n)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 매번 sum(d)를 다시 계산하는 부분을 개선했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 결과 비교&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLVo8D/btsJUWNM65T/Y7LqtEhyzSSITMGDbXIWaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLVo8D/btsJUWNM65T/Y7LqtEhyzSSITMGDbXIWaK/img.png&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;514&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.7513%; margin-right: 10px;&quot; data-widthpercent=&quot;50.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLVo8D/btsJUWNM65T/Y7LqtEhyzSSITMGDbXIWaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLVo8D%2FbtsJUWNM65T%2FY7LqtEhyzSSITMGDbXIWaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;702&quot; height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxWsv5/btsJWpOq4GZ/4vGh9JKPtQkykVYHFHCkNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxWsv5/btsJWpOq4GZ/4vGh9JKPtQkykVYHFHCkNk/img.png&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;518&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.0859%;&quot; data-widthpercent=&quot;49.66&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxWsv5/btsJWpOq4GZ/4vGh9JKPtQkykVYHFHCkNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxWsv5%2FbtsJWpOq4GZ%2F4vGh9JKPtQkykVYHFHCkNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;698&quot; height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 테스트에서 확연한 차이가 보인다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;다시 한번 짧은 코드가 좋은 코드가 아님을 명심,,&lt;/u&gt;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/157</guid>
      <comments>https://ginghambagle.tistory.com/157#entry157comment</comments>
      <pubDate>Sat, 5 Oct 2024 01:16:16 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 큰 수 만들기: 문자열보다 리스트 사용하기</title>
      <link>https://ginghambagle.tistory.com/156</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 링크&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42883&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42883&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1728058983647&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42883&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/o0GLy/hyXeeZZ8j8/bz2mQoRg8IzhT4m1RrH5Qk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bhL7P5/hyXeaiZGJt/RhonKkAyuot15hsHE6MHqk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42883&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42883&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/o0GLy/hyXeeZZ8j8/bz2mQoRg8IzhT4m1RrH5Qk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bhL7P5/hyXeaiZGJt/RhonKkAyuot15hsHE6MHqk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍을 하다 보면, 코드가 짧을수록 좋다는 착각에 빠질 때가 있다. 나는 문제를 풀 때 문자열이 주어지면, 바로 그 문자열로만 해결하려는 경향이 있다. 하지만 짧은 코드가 항상 좋은 코드를 의미하는 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열과 리스트의 차이점, 그리고 언제 리스트를 사용하는 것이 더 좋은가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ginghambagle.tistory.com/155&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ginghambagle.tistory.com/155&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1727885024142&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;mutable(변경 가능)과 immutable(변경 불가능)&quot; data-og-description=&quot;파이썬에서 리스트(List)는 mutable(변경 가능)하고, 문자열(String)은 immutable(변경 불가능)하다는 의미는 그 데이터 타입이 변경 가능한지, 즉 그 안에 저장된 요소를 직접 수정할 수 있는지와 관련이&quot; data-og-host=&quot;ginghambagle.tistory.com&quot; data-og-source-url=&quot;https://ginghambagle.tistory.com/155&quot; data-og-url=&quot;https://ginghambagle.tistory.com/155&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ccfwAB/hyXayS4Oft/G0hR6uz155jvmhXBhxqkI0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/xoXix/hyXaEMw5I5/eG1KMNBzhoUWzfkNem8wCk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hXkN9/hyXect1WKH/0VBIDktY87Ydbq8ptaTkf0/img.png?width=264&amp;amp;height=200&amp;amp;face=0_0_264_200&quot;&gt;&lt;a href=&quot;https://ginghambagle.tistory.com/155&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ginghambagle.tistory.com/155&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ccfwAB/hyXayS4Oft/G0hR6uz155jvmhXBhxqkI0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/xoXix/hyXaEMw5I5/eG1KMNBzhoUWzfkNem8wCk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hXkN9/hyXect1WKH/0VBIDktY87Ydbq8ptaTkf0/img.png?width=264&amp;amp;height=200&amp;amp;face=0_0_264_200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;mutable(변경 가능)과 immutable(변경 불가능)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;파이썬에서 리스트(List)는 mutable(변경 가능)하고, 문자열(String)은 immutable(변경 불가능)하다는 의미는 그 데이터 타입이 변경 가능한지, 즉 그 안에 저장된 요소를 직접 수정할 수 있는지와 관련이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ginghambagle.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문자열은 immutable하다&lt;/h3&gt;
&lt;pre id=&quot;code_1727882904078&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(number, k):
    answer = ''
    for n in number:
        while answer and answer[-1] &amp;lt; n and k &amp;gt; 0:
            answer = answer[:-1]
            k -= 1
        answer += n
    if k &amp;gt; 0:
        answer = answer[:-k]
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 코드는 문자열 answer를 계속해서 반복적으로 생성하고 덧붙이며 수정해 나가는 방식이다. 문자열은 &lt;b&gt;immutable&lt;/b&gt;하기 때문에 answer += n이 실행될 때마다 새로운 문자열이 생성되고, 메모리 할당과 복사 과정이 포함되어 있다. 문자열이 길어질수록 성능에 부담을 줄 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리스트는 mutable하다&lt;/h3&gt;
&lt;pre id=&quot;code_1727882917783&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(number, k):
    collected = []
    for i, num in enumerate(number):
        while len(collected) &amp;gt; 0 and collected[-1] &amp;lt; num and k &amp;gt; 0:
            collected.pop()
            k -= 1
        if k == 0:
            collected += list(number[i:])
            break
        collected.append(num)
        
    collected = collected[:-k] if k &amp;gt; 0 else collected
    answer = ''.join(collected)
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 코드는 리스트를 사용해서 필요한 조작을 수행하고, 마지막에 리스트를 문자열로 변환하여 반환한다. 리스트는 &lt;b&gt;mutable&lt;/b&gt;하기 때문에 요소를 더하거나 빼는 작업이 효율적이다. append, pop 등을 통해 리스트를 수정할 때 새로운 객체를 생성하지 않고 기존 리스트를 변경하기 때문에 성능이 더 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과 비교&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/menWO/btsJUjgGciM/13v2hHbpuS390pHx0YAodk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/menWO/btsJUjgGciM/13v2hHbpuS390pHx0YAodk/img.png&quot; data-origin-width=&quot;1414&quot; data-origin-height=&quot;588&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4815%; margin-right: 10px;&quot; data-widthpercent=&quot;50.06&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/menWO/btsJUjgGciM/13v2hHbpuS390pHx0YAodk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmenWO%2FbtsJUjgGciM%2F13v2hHbpuS390pHx0YAodk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1414&quot; height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mp9Sa/btsJT71PoYO/5YejUfVtl41ZDYHieMqgLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mp9Sa/btsJT71PoYO/5YejUfVtl41ZDYHieMqgLK/img.png&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;592&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.94&quot; style=&quot;width: 49.3557%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mp9Sa/btsJT71PoYO/5YejUfVtl41ZDYHieMqgLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmp9Sa%2FbtsJT71PoYO%2F5YejUfVtl41ZDYHieMqgLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1420&quot; height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;왼: 문자열, 오: 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 7-10에서 큰 차이를 보인다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열을 사용하고 그대로 반환하는 것이 코드 작성자에게는 편리하지만 컴퓨터의 관점에서 &lt;b&gt;효율적인 코드&lt;/b&gt;를 작성하는 것이 중요하다. 성능이나 메모리 사용량을 고려해야 할 때는, mutable한 리스트 같은 자료구조를 적극적으로 사용하는 것이 더 나은 선택일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 코드를 작성할 때는 입력 데이터의 특성과 처리 방법을 고민하고, 문자열 대신 리스트를 사용하는 것이 적합한 상황인지 신경 써보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/156</guid>
      <comments>https://ginghambagle.tistory.com/156#entry156comment</comments>
      <pubDate>Thu, 3 Oct 2024 01:02:40 +0900</pubDate>
    </item>
    <item>
      <title>mutable(변경 가능)과 immutable(변경 불가능)</title>
      <link>https://ginghambagle.tistory.com/155</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬에서 &lt;b&gt;리스트(List)&lt;/b&gt;는 &lt;b&gt;mutable(변경 가능)&lt;/b&gt;하고, &lt;b&gt;문자열(String)&lt;/b&gt;은 &lt;b&gt;immutable(변경 불가능)&lt;/b&gt;하다는 의미는 그 데이터 타입이 변경 가능한지, 즉 그 안에 저장된 요소를 직접 수정할 수 있는지와 관련이 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;리스트 (mutable)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;mutable(변경 가능)&lt;/b&gt;하다는 것은 리스트의 요소를 &lt;b&gt;직접 수정&lt;/b&gt;할 수 있다는 뜻입니다. 리스트의 특정 요소를 바꾸거나, 요소를 추가하거나, 삭제할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1727879873408&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;my_list = [1, 2, 3]
my_list[0] = 10  # 리스트의 첫 번째 요소를 10으로 변경
print(my_list)  # 출력: [10, 2, 3]

my_list.append(4)  # 새로운 요소 추가
print(my_list)  # 출력: [10, 2, 3, 4]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 리스트는 원래 있던 값이 변하고, 새로운 값을 추가하거나 제거할 수 있습니다. 즉, &lt;b&gt;mutable&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;하다는 것은 데이터를 &quot;수정&quot;할 수 있다는 의미입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;문자열 (immutable)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;immutable(변경 불가능)&lt;/b&gt;하다는 것은 한 번 생성된 문자열을 &lt;b&gt;직접 수정할 수 없다는&lt;/b&gt; 뜻입니다. 즉, 문자열의 특정 문자를 바꾸거나, 문자열 중 일부를 삭제하는 것이 불가능합니다. 만약 문자열을 변경하려면, &lt;b&gt;새로운 문자열을 만들어야&lt;/b&gt; 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1727879929284&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;my_string = &quot;hello&quot;
# my_string[0] = 'H'  # 오류 발생: 문자열은 변경할 수 없음
new_string = &quot;H&quot; + my_string[1:]  # 새로운 문자열을 만듦
print(new_string)  # 출력: &quot;Hello&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 my_string[0] = 'H'는 오류를 발생시킵니다. 문자열을 수정하려면 항상 새로운 문자열을 생성하는 방식으로 작업해야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;요약:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;mutable (변경 가능):&lt;/b&gt; 리스트처럼 한 번 생성된 객체의 내부 값을 변경할 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;immutable (변경 불가능):&lt;/b&gt; 문자열처럼 한 번 생성된 객체의 내부 값을 변경할 수 없고, 값을 바꾸려면 새로운 객체를 만들어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;파이썬에서의 mutable(변경 가능)과 immutable(변경 불가능) 데이터 타입&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Mutable (변경 가능) 데이터 타입:&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;List (리스트)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: [1, 2, 3]&lt;/li&gt;
&lt;li&gt;요소를 추가, 삭제, 수정할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Dictionary (딕셔너리)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: {'key1': 'value1', 'key2': 'value2'}&lt;/li&gt;
&lt;li&gt;키-값 쌍을 추가하거나 삭제하고, 값을 수정할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Set (집합)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: {1, 2, 3}&lt;/li&gt;
&lt;li&gt;요소를 추가하거나 삭제할 수 있음. 중복된 값을 허용하지 않음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Bytearray&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: bytearray(b&quot;hello&quot;)&lt;/li&gt;
&lt;li&gt;바이트 배열로, 개별 바이트 값을 변경할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Immutable (변경 불가능) 데이터 타입:&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;String (문자열)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: &quot;hello&quot;&lt;/li&gt;
&lt;li&gt;문자열의 개별 문자를 변경할 수 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Tuple (튜플)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: (1, 2, 3)&lt;/li&gt;
&lt;li&gt;한 번 생성된 튜플은 수정할 수 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;frozenset (고정 집합)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: frozenset([1, 2, 3])&lt;/li&gt;
&lt;li&gt;집합처럼 동작하지만, 요소를 추가하거나 삭제할 수 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Bytes&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: b&quot;hello&quot;&lt;/li&gt;
&lt;li&gt;바이트 배열의 불변 버전. 변경할 수 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Numbers (숫자형)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;int&lt;/b&gt;, &lt;b&gt;float&lt;/b&gt;, &lt;b&gt;complex&lt;/b&gt; 등.&lt;/li&gt;
&lt;li&gt;예시: 42, 3.14&lt;/li&gt;
&lt;li&gt;숫자는 한 번 생성되면 값이 변하지 않음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Python</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/155</guid>
      <comments>https://ginghambagle.tistory.com/155#entry155comment</comments>
      <pubDate>Wed, 2 Oct 2024 23:40:16 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스/SQL] 가격이 제일 비싼 식품의 정보 출력하기: 정렬 vs 서브쿼리</title>
      <link>https://ginghambagle.tistory.com/154</link>
      <description>&lt;ol style=&quot;list-style-type: decimal; color: #263747; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: none; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://school.programmers.co.kr/learn/challenges&quot;&gt;코딩테스트 연습 &amp;gt;&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://school.programmers.co.kr/learn/courses/30/parts/17043&quot;&gt;SUM, MAX, MIN&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;gt; 가격이 제일 비싼 식품의 정보 출력하기&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 정렬-&amp;gt;1개만 출력&lt;/p&gt;
&lt;pre id=&quot;code_1721982069393&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_CD, CATEGORY, PRICE
FROM FOOD_PRODUCT
ORDER BY PRICE DESC
LIMIT 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. max&lt;/p&gt;
&lt;pre id=&quot;code_1721982078757&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_CD, CATEGORY, PRICE
FROM FOOD_PRODUCT
WHERE PRICE = (SELECT MAX(PRICE) FROM FOOD_PRODUCT);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성능 비교&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;서브쿼리 vs. 정렬 및 제한&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;쿼리 1번&lt;/b&gt;은 테이블을 가격 기준으로 내림차순 정렬한 다음 상위 한 행만 가져옵니다. 인덱스가 제대로 설정되어 있다면, 이 방식이 더 효율적일 수 있습니다. 인덱스를 사용하여 정렬 작업이 빠르게 수행될 수 있기 때문입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쿼리 2번&lt;/b&gt;은 서브쿼리를 사용하여 FOOD_PRODUCT 테이블의 최대 가격을 먼저 계산합니다. 그런 다음 이 최대 가격과 일치하는 행을 찾습니다. 서브쿼리를 사용하기 때문에 두 번의 검색 작업이 필요합니다. 이 방식은 특히 대용량 테이블에서 성능에 영향을 미칠 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인덱스 사용 여부&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쿼리 1번&lt;/b&gt;은 가격 기준으로 정렬하는 작업에 인덱스를 효과적으로 활용할 수 있습니다. 가격에 인덱스가 있다면, 내림차순 정렬과 LIMIT 1 작업이 빠르게 수행될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쿼리 2번&lt;/b&gt;은 서브쿼리가 최대 가격을 찾는 작업을 먼저 수행합니다. 이 작업에 인덱스가 사용될 수 있습니다. 그러나 메인 쿼리가 다시 한 번 검색을 수행해야 하므로, 인덱스를 활용하더라도 효율성이 떨어질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 &lt;b&gt;쿼리 1번&lt;/b&gt;이 성능 면에서 더 나을 가능성이 높습니다. 이유는 정렬과 LIMIT를 사용하여 인덱스를 효율적으로 활용할 수 있기 때문입니다. 물론, 실제 성능은 데이터베이스 엔진, 데이터의 분포, 인덱스의 존재 여부 등에 따라 달라질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 대용량 데이터셋을 다루고 있고, PRICE 컬럼에 인덱스가 설정되어 있다면 쿼리 2번을 사용하는 것이 더 나은 선택이 될 것입니다. 반면에, 데이터베이스의 구체적인 상황을 고려하여 실제 성능 테스트를 수행하는 것도 좋은 방법입니다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/154</guid>
      <comments>https://ginghambagle.tistory.com/154#entry154comment</comments>
      <pubDate>Fri, 26 Jul 2024 17:26:19 +0900</pubDate>
    </item>
    <item>
      <title>MySQL Workbench | ERROR: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') ENGINE = InnoDB' at line 11</title>
      <link>https://ginghambagle.tistory.com/150</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL Workbench를 이용해서 원격 서버에 있는 MariaDB에 디비 구축을 해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이어그램으로 작성하면 한눈에 테이블간 관계 등을 눈으로 쉽게 확인할 수 있어서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EER Diagram으로 모델 작성 후 Forward Engineer를 통해 데이터베이스에 테이블 생성을 하려고 했는데 제목과 같은 오류가 났다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;ERROR:&amp;nbsp;Error&amp;nbsp;1064:&amp;nbsp;You&amp;nbsp;have&amp;nbsp;an&amp;nbsp;error&amp;nbsp;in&amp;nbsp;your&amp;nbsp;SQL&amp;nbsp;syntax;&amp;nbsp;check&amp;nbsp;the&amp;nbsp;manual&amp;nbsp;that&amp;nbsp;corresponds&amp;nbsp;to&amp;nbsp;your&amp;nbsp;MariaDB&amp;nbsp;server&amp;nbsp;version&amp;nbsp;for&amp;nbsp;the&amp;nbsp;right&amp;nbsp;syntax&amp;nbsp;to&amp;nbsp;use&amp;nbsp;near&amp;nbsp;')&amp;nbsp;ENGINE&amp;nbsp;=&amp;nbsp;InnoDB'&amp;nbsp;at&amp;nbsp;line&amp;nbsp;11&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러메세지 검색을 통해 이 에러가 내 db 버전과 워크벤치 설정의 타겟 db버전이 맞지 않아서 생기는 에러라는 것을 알게 되었다. (기본 타겟 db버전은 8.0.32로 설정되어 있었다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  내 MariaDB 버전 확인&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sHKQY/btr2IvwPm6m/8YRfXpKwpIQeeE0P7y3Eq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sHKQY/btr2IvwPm6m/8YRfXpKwpIQeeE0P7y3Eq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sHKQY/btr2IvwPm6m/8YRfXpKwpIQeeE0P7y3Eq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsHKQY%2Fbtr2IvwPm6m%2F8YRfXpKwpIQeeE0P7y3Eq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;136&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접속 시 나오는 웰컴 메세지나&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;mysql -V&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mysql -V 명령어를 통해 확인 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  호환되는 MySQL 버전 확인&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL MariaDB version mapping 검색어로 아래 참고사이트를 찾았고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MariaDB 10.3은 MySQL 5.7과 호환된다는 것을 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  MySQL Workbench 설정 변경&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRHARt/btr2OrAJTSF/pQZ3ifCeEiNCtKWXuilpok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRHARt/btr2OrAJTSF/pQZ3ifCeEiNCtKWXuilpok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRHARt/btr2OrAJTSF/pQZ3ifCeEiNCtKWXuilpok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRHARt%2Fbtr2OrAJTSF%2FpQZ3ifCeEiNCtKWXuilpok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1171&quot; height=&quot;862&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노란네모부분을 클릭하면 preferences 변경을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cphUqK/btr2Nw95hun/38McSZIpVW9oKlvgfFKwZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cphUqK/btr2Nw95hun/38McSZIpVW9oKlvgfFKwZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cphUqK/btr2Nw95hun/38McSZIpVW9oKlvgfFKwZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcphUqK%2Fbtr2Nw95hun%2F38McSZIpVW9oKlvgfFKwZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;528&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tP15s/btr2D05zJiF/L6YfLBktUL4XilW651bHD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tP15s/btr2D05zJiF/L6YfLBktUL4XilW651bHD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tP15s/btr2D05zJiF/L6YfLBktUL4XilW651bHD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtP15s%2Fbtr2D05zJiF%2FL6YfLBktUL4XilW651bHD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;704&quot; height=&quot;530&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Modeling -&amp;gt; MySQL에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Default Target MySQL Version을 5.7로 변경하고 저장해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3dZRH/btr2C9vckiK/BNzb3wU7vddIkOoXFdk3S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3dZRH/btr2C9vckiK/BNzb3wU7vddIkOoXFdk3S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3dZRH/btr2C9vckiK/BNzb3wU7vddIkOoXFdk3S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3dZRH%2Fbtr2C9vckiK%2FBNzb3wU7vddIkOoXFdk3S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;548&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 Forward Engineer를 실행하면&amp;nbsp;정상적으로&amp;nbsp;동작이&amp;nbsp;완료되고&amp;nbsp;데이터베이스에&amp;nbsp;테이블이&amp;nbsp;생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mariadb.com/kb/en/mariadb-vs-mysql-compatibility/#mysql-57&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mariadb.com/kb/en/mariadb-vs-mysql-compatibility/#mysql-57&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>1064에러</category>
      <category>forwardengineer</category>
      <category>MariaDB</category>
      <category>MySQL</category>
      <category>Workbench</category>
      <category>호환</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/150</guid>
      <comments>https://ginghambagle.tistory.com/150#entry150comment</comments>
      <pubDate>Wed, 8 Mar 2023 16:04:21 +0900</pubDate>
    </item>
    <item>
      <title>MantisBT | 첨부파일 최대크기 늘리기</title>
      <link>https://ginghambagle.tistory.com/149</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;mantisbt에서 이슈 등록할때 첨부파일을 함께 올릴 수 있는데 최대 크기는 기본 2048KiB로 설정돼있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;164&quot; data-origin-height=&quot;83&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9WK3S/btrZsGivOSg/Gp5JC2pKNjP5bNwX4FL9x0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9WK3S/btrZsGivOSg/Gp5JC2pKNjP5bNwX4FL9x0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9WK3S/btrZsGivOSg/Gp5JC2pKNjP5bNwX4FL9x0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9WK3S%2FbtrZsGivOSg%2FGp5JC2pKNjP5bNwX4FL9x0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;164&quot; height=&quot;83&quot; data-origin-width=&quot;164&quot; data-origin-height=&quot;83&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서를 찾아보면&amp;nbsp; g_max_file_size를 변경하면 된다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;config_inc.php&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;$g_max_file_size&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Maximum file size that can be uploaded. Default value is about 5 MiB. The maximum size is also affected by the PHP options post_max_size (default 8 MiB), upload_max_filesize (default 2 MiB) and memory_limit (default 128 MiB) specified in php.ini.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 config_defaults_inc.php파일을 보면 기본값이 5MiB로 설정되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tWO1y/btrZxJ6wDUh/K2n7EKnzMGKCakJ5dsP3rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tWO1y/btrZxJ6wDUh/K2n7EKnzMGKCakJ5dsP3rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tWO1y/btrZxJ6wDUh/K2n7EKnzMGKCakJ5dsP3rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtWO1y%2FbtrZxJ6wDUh%2FK2n7EKnzMGKCakJ5dsP3rK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;207&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;config_inc.php파일에서 값을 원하는 값으로 설정해서 덮어씌워준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;347&quot; data-origin-height=&quot;81&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6H0KW/btrZz0md9Ma/4BVE9RmOwTrBtS3Y0Ewcck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6H0KW/btrZz0md9Ma/4BVE9RmOwTrBtS3Y0Ewcck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6H0KW/btrZz0md9Ma/4BVE9RmOwTrBtS3Y0Ewcck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6H0KW%2FbtrZz0md9Ma%2F4BVE9RmOwTrBtS3Y0Ewcck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;347&quot; height=&quot;81&quot; data-origin-width=&quot;347&quot; data-origin-height=&quot;81&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 업로드 가능한 최대 파일 크기는 변하지 않는데 php.ini파일에서 공식문서에 언급된 두 변수를 바꿔주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값이 5인데 업로드 가능 최대 크기가 2인 이유도 php.ini파일의 upload_max_filesize의 기본값이 2MiB로 설정되어 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;php.ini&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;upload_max_filesize&amp;nbsp;int&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The maximum size of an uploaded file. &lt;a href=&quot;https://www.php.net/manual/en/ini.core.php#ini.post-max-size&quot;&gt;post_max_size&lt;/a&gt; must be larger than this value.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post_max_size는 upload_max_filesize값보다 커야 한다고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UuvLr/btrZz1ZLivj/uW4KyuBNW5SwMM51Xsrku0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UuvLr/btrZz1ZLivj/uW4KyuBNW5SwMM51Xsrku0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UuvLr/btrZz1ZLivj/uW4KyuBNW5SwMM51Xsrku0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUuvLr%2FbtrZz1ZLivj%2FuW4KyuBNW5SwMM51Xsrku0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;708&quot; height=&quot;141&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhU9uV/btrZzn3fBQl/sKT4EVLnGv69DqEQy2SpLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhU9uV/btrZzn3fBQl/sKT4EVLnGv69DqEQy2SpLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhU9uV/btrZzn3fBQl/sKT4EVLnGv69DqEQy2SpLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhU9uV%2FbtrZzn3fBQl%2FsKT4EVLnGv69DqEQy2SpLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;409&quot; height=&quot;101&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;101&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 값을 넉넉하게 바꿔준 후 서버를 다시 시작하고 mantisbt에 접속해보면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;188&quot; data-origin-height=&quot;93&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/27Mkc/btrZz1SWWO3/23VM4NkTK9oExU5MCZ6RQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/27Mkc/btrZz1SWWO3/23VM4NkTK9oExU5MCZ6RQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/27Mkc/btrZz1SWWO3/23VM4NkTK9oExU5MCZ6RQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F27Mkc%2FbtrZz1SWWO3%2F23VM4NkTK9oExU5MCZ6RQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;188&quot; height=&quot;93&quot; data-origin-width=&quot;188&quot; data-origin-height=&quot;93&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 첨부파일 최대 크기가 변경된 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@leedongins/133&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://brunch.co.kr/@leedongins/133&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.mantisbt.org/docs/master/en-US/Admin_Guide/html/admin.config.uploads.html&quot;&gt;https://www.mantisbt.org/docs/master/en-US/Admin_Guide/html/admin.config.uploads.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize&quot;&gt;https://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>MantisBT</category>
      <category>첨부파일</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/149</guid>
      <comments>https://ginghambagle.tistory.com/149#entry149comment</comments>
      <pubDate>Fri, 17 Feb 2023 19:30:02 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 scp 명령어로 아마존 리모트 서버에 파일 복사하기</title>
      <link>https://ginghambagle.tistory.com/148</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;scp: Secure Copy&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;scp 명령어는 리모트 서버로(부터) 파일을 안전하게 복사할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일이 현재 디렉토리에 있으면 파일명만, 아니라면 full path가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법&lt;/p&gt;
&lt;pre id=&quot;code_1676529899823&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;scp 복사할파일경로 가져다놓을디렉토리경로&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;현재 디렉토리의 로컬파일 -&amp;gt; 리모트 디렉토리&lt;/h4&gt;
&lt;pre id=&quot;code_1676528276102&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;scp -i my_key.pem hi.txt username@퍼블릭ip:/경로/경로/경로&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리모트서버에 hi라는 디렉토리를 하나 만들고 실험해봤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yz9BU/btrZzGuCQtC/gPGwkLK7zf5D0hGsP0vCdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yz9BU/btrZzGuCQtC/gPGwkLK7zf5D0hGsP0vCdk/img.png&quot; data-alt=&quot;리모트서버&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yz9BU/btrZzGuCQtC/gPGwkLK7zf5D0hGsP0vCdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyz9BU%2FbtrZzGuCQtC%2FgPGwkLK7zf5D0hGsP0vCdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;407&quot; height=&quot;72&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리모트서버&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 로컬에서 hi.txt를 만들고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;213&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tjCdh/btrZsHBCM0T/7BYuN4sYh0xEGsNBkNTKhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tjCdh/btrZsHBCM0T/7BYuN4sYh0xEGsNBkNTKhK/img.png&quot; data-alt=&quot;로컬&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tjCdh/btrZsHBCM0T/7BYuN4sYh0xEGsNBkNTKhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtjCdh%2FbtrZsHBCM0T%2F7BYuN4sYh0xEGsNBkNTKhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;213&quot; height=&quot;432&quot; data-origin-width=&quot;213&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로컬&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;77&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjD7zJ/btrZxfj6h2m/wkj1PAUkoSxLcbln2EEU7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjD7zJ/btrZxfj6h2m/wkj1PAUkoSxLcbln2EEU7k/img.png&quot; data-alt=&quot;로컬&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjD7zJ/btrZxfj6h2m/wkj1PAUkoSxLcbln2EEU7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjD7zJ%2FbtrZxfj6h2m%2Fwkj1PAUkoSxLcbln2EEU7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;974&quot; height=&quot;77&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;77&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로컬&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리모트 서버에 파일이 복사되었다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0PM8d/btrZzHmMuYN/sRlRPyNwGGuskz3h7sKRXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0PM8d/btrZzHmMuYN/sRlRPyNwGGuskz3h7sKRXk/img.png&quot; data-alt=&quot;리모트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0PM8d/btrZzHmMuYN/sRlRPyNwGGuskz3h7sKRXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0PM8d%2FbtrZzHmMuYN%2FsRlRPyNwGGuskz3h7sKRXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;432&quot; height=&quot;95&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리모트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nRbqL/btrZzav0yY9/vfPNXeGqpUGQEGSu23ApJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nRbqL/btrZzav0yY9/vfPNXeGqpUGQEGSu23ApJK/img.png&quot; data-alt=&quot;리모트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nRbqL/btrZzav0yY9/vfPNXeGqpUGQEGSu23ApJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnRbqL%2FbtrZzav0yY9%2FvfPNXeGqpUGQEGSu23ApJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;186&quot; height=&quot;258&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;258&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리모트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리모트 서버의 파일 -&amp;gt; 현재 로컬 디렉토리&lt;/h4&gt;
&lt;pre id=&quot;code_1676529600701&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;scp -i my_key.pem username@주소:/경로/경로/파일명 ./&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 실험을 해봤지만 모자이크하다가 현타와서 이만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전에 이 명령어를 몰라서 filezilla를 이용해서 리모트 서버에 파일을 복사했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램을 쓰는게 훨씬 편하지만 별도 프로그램 설치 없이 터미널에서 바로 파일 복사하는 법도 알아두면 좋을 것 같다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>리모트서버로</category>
      <category>터미널에서</category>
      <category>파일전송</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/148</guid>
      <comments>https://ginghambagle.tistory.com/148#entry148comment</comments>
      <pubDate>Thu, 16 Feb 2023 15:45:15 +0900</pubDate>
    </item>
    <item>
      <title>Go | Reference types (pointers)</title>
      <link>https://ginghambagle.tistory.com/147</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;포인터는 메모리에서 특정 위치를 가리키는것이다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1674980445804&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func main() {
	x := 10
	
	// x(10이저장)돼있는 메모리의 주소를 myFirstPointer에 저장
	// &amp;amp;x: x의 레퍼런스
	myFirstPointer := &amp;amp;x  
	
	// *: 메모리에서 myFirstPointer가 가리키는주소에 가서 그 내용을 15로바꿔라 
	*myFirstPointer = 15
	// x: 15
}

func changeValueOfPointer(num *int) {
	*num =25
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인터 왜쓰냐:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 패스하고 리턴하지 않고도,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수를 포함하지 않는 스코프에서도 변수의 값을 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접접근가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1674980810089&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func main() {
	x := 10

	myFirstPointer := &amp;amp;x  
	
	*myFirstPointer = 15
	// x: 15

	changeValueOfPointer(&amp;amp;x)
	// x: 25
}

func changeValueOfPointer(num *int) {
	*num =25
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Go</category>
      <category>go</category>
      <category>goland</category>
      <category>포인터</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/147</guid>
      <comments>https://ginghambagle.tistory.com/147#entry147comment</comments>
      <pubDate>Sun, 29 Jan 2023 17:28:17 +0900</pubDate>
    </item>
    <item>
      <title>Go | Aggregate types (arrays, struct)</title>
      <link>https://ginghambagle.tistory.com/146</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;  배열&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go에서 배열은 다른 언어에서만큼 많이 쓰이지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Go에는 slice가 있기 때문. (배열비슷한데 추가적인 기능이 있음)&lt;/p&gt;
&lt;pre id=&quot;code_1674973058877&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//선언: [길이]타입
var myStrings [3]string

//할당
myStrings[0] = &quot;cat&quot;
myStrings[1] = &quot;dog&quot;
myStrings[2] = &quot;fish&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  struct&lt;/h3&gt;
&lt;pre id=&quot;code_1674973173145&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Car struct {
    NumberOfTires int
    Luxury bool
    BucketSeats bool
    Make string
    Model string
    Year int
}

func main() {
	// var myCar Car
    // myCar.NumberOfTires = 4
    // myCar.Luxury = false
    // ...
    
    // ---&amp;gt;
    myCar := Car{
    	NumberOfTires: 4,
        Luxury: true,
        BucketSeats: true,
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Go</category>
      <category>go</category>
      <category>golang</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/146</guid>
      <comments>https://ginghambagle.tistory.com/146#entry146comment</comments>
      <pubDate>Sun, 29 Jan 2023 15:24:02 +0900</pubDate>
    </item>
    <item>
      <title>Go | 기본타입 (numbers, strings, booleans)</title>
      <link>https://ginghambagle.tistory.com/145</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;  number&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;int&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;uint: 0과 양수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;int16: 16비트 인티저&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;int32: 32비트...&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;int64: 64...&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 int(숫자)타입들이 있음?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램이 폰 옛날컴 현재컴 등 어떤 아키텍쳐에서 컴파일될지 모르기 때문에 다양한 종류가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절대로 확실하게 64비트 아키텍처용 만든다면 int64쓰는게 조오금 낫다. 하지만 그냥 int를 쓰는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;float&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;float32: 32비트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;float64: 64비트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 float는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이즈에 따라서 골라서 쓰기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  string&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트링은 go에서 이뮤터블 변경 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;myString := &quot;홍길동&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;myString = &quot;김말동&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 바꾸는게 아니라 새로운 스트링을 생성해서 변수에 할당하는것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 엄청큰 나노세컨드 단위가 중요한 프로그램에서 문제가 될수 있긴 하다. 그치만 대부분의 경우 그냥 뮤터블이라고 생각해도 문제 없을것(하지만 아님!!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  boolean&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;true false만 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0 할당: 에러, 스트링할당: 에러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Go</category>
      <category>go</category>
      <category>golang</category>
      <category>Types</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/145</guid>
      <comments>https://ginghambagle.tistory.com/145#entry145comment</comments>
      <pubDate>Sun, 29 Jan 2023 15:10:18 +0900</pubDate>
    </item>
    <item>
      <title>MantisBT | 프로젝트 생성 권한 변경하기</title>
      <link>https://ginghambagle.tistory.com/144</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;mantisbt는 커스터마이징이 가능한 무료 이슈 관리 툴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://computingforgeeks.com/install-and-configure-mantis-bug-tracker-on-ubuntu/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://computingforgeeks.com/install-and-configure-mantis-bug-tracker-on-ubuntu/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크를 보고 우분투 서버에 설치를 했다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨티스 유저의 권한은 보기가능, 보고가능, 갱신가능, 개발자, 매니저, 관리자(&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;VIEWER, REPORTER, UPDATER, DEVELOPER, MANAGER and ADMINISTRATOR&lt;/span&gt;)로 5개 권한이 있다. 뒤로 갈수록 높은 권한을 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 관련해서는 각각 아래 작업이 가능하다.(기본값)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1147&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBhzUt/btrVT5ZO95h/aOscymHpVnhLyTfYQSJ2tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBhzUt/btrVT5ZO95h/aOscymHpVnhLyTfYQSJ2tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBhzUt/btrVT5ZO95h/aOscymHpVnhLyTfYQSJ2tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBhzUt%2FbtrVT5ZO95h%2FaOscymHpVnhLyTfYQSJ2tK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1147&quot; height=&quot;319&quot; data-origin-width=&quot;1147&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/trq2k/btrVVRsI0Cy/vd0XSPCRVVGBLfXW9UV4q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/trq2k/btrVVRsI0Cy/vd0XSPCRVVGBLfXW9UV4q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/trq2k/btrVVRsI0Cy/vd0XSPCRVVGBLfXW9UV4q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftrq2k%2FbtrVVRsI0Cy%2Fvd0XSPCRVVGBLfXW9UV4q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;216&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매니저 권한인 manager1로 로그인한 상황. 프로젝트 생성이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 매니저도 프로젝트 생성이 가능하도록 만들고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디폴트 환경 설정값을 보기 위해 mantisbt 설치 위치의 &lt;b&gt;config_defaults_inc.php&lt;/b&gt; 파일을 열어 본다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjFgsQ/btrVTm1R309/nvoQrQ4aikQdxZL14hKeV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjFgsQ/btrVTm1R309/nvoQrQ4aikQdxZL14hKeV0/img.png&quot; data-alt=&quot;config_defaults_inc.php&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjFgsQ/btrVTm1R309/nvoQrQ4aikQdxZL14hKeV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjFgsQ%2FbtrVTm1R309%2FnvoQrQ4aikQdxZL14hKeV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;411&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;config_defaults_inc.php&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 프로젝트 생성할 수 있는 최소 권한이 ADMINISTRATOR로 설정돼 있는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값을 변경하고싶다면 &lt;b&gt;config_inc.php&lt;/b&gt; 파일에 해당 변수를 오버라이딩 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일은 mantis가 설치된 위치의 config 디렉토리 내에 위치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;config_defaults_inc.php를 직접 변경하지 않는 이유는 mantisbt 업그레이드 등을 위해 백업할 때 기본값에서 변경사항만 담긴 config_inc.php파일만 백업하면 되기 때문이다 등등의 이유가 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBNXfk/btrVXCWdVCy/6tKNJTRkwM21rqM3nhkjSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBNXfk/btrVXCWdVCy/6tKNJTRkwM21rqM3nhkjSK/img.png&quot; data-alt=&quot;config_inc.php&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBNXfk/btrVXCWdVCy/6tKNJTRkwM21rqM3nhkjSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBNXfk%2FbtrVXCWdVCy%2F6tKNJTRkwM21rqM3nhkjSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;102&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;102&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;config_inc.php&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 config_inc.php에 프로젝트 생성 최소권한을 MANAGER로 설정해주고 저장후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버를 재시작 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1673410533991&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo systemctl restart apache2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 MANAGER권한을 가진 manager1로 로그인 후 프로젝트 관리 페이지를 보면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vRgFq/btrVWyzGNIs/8jJ4tPyZs4IlbveDkMr7d0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vRgFq/btrVWyzGNIs/8jJ4tPyZs4IlbveDkMr7d0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vRgFq/btrVWyzGNIs/8jJ4tPyZs4IlbveDkMr7d0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvRgFq%2FbtrVWyzGNIs%2F8jJ4tPyZs4IlbveDkMr7d0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;270&quot; height=&quot;225&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1283&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OmkKP/btrVUxhjUqb/czl2S36K4EnCSXdtiO6nh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OmkKP/btrVUxhjUqb/czl2S36K4EnCSXdtiO6nh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OmkKP/btrVUxhjUqb/czl2S36K4EnCSXdtiO6nh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOmkKP%2FbtrVUxhjUqb%2Fczl2S36K4EnCSXdtiO6nh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1283&quot; height=&quot;316&quot; data-origin-width=&quot;1283&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 매니저권한도 프로젝트를 생성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yckim.wordpress.com/2010/02/22/mantis-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95%EC%9D%98-%EB%B9%84%EB%B0%80/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://yckim.wordpress.com/2010/02/22/mantis-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95%EC%9D%98-%EB%B9%84%EB%B0%80/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.mantisbt.org/docs/master/en-US/Admin_Guide/html/admin.user.access.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.mantisbt.org/docs/master/en-US/Admin_Guide/html/admin.user.access.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>Customizing</category>
      <category>Mantis</category>
      <category>MantisBT</category>
      <category>맨티스</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/144</guid>
      <comments>https://ginghambagle.tistory.com/144#entry144comment</comments>
      <pubDate>Wed, 11 Jan 2023 13:42:57 +0900</pubDate>
    </item>
    <item>
      <title>NestJS | TypeORM: entity 정의(soft delete, 추상클래스)</title>
      <link>https://ginghambagle.tistory.com/143</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️ soft delete&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전에는 soft delete를 위해서 is_active라는 컬럼을 추가해서 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;삭제 요청이 오면 실제 삭제 대신 is_active=false로 바꿔주는 작업을 했었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeORM에서는 soft delete를 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드를 삭제하는 대신 @DeleteDateColumn()이 붙어있는 컬럼(날짜)을 업데이트한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 컬럼이 포함되면 데이터를 읽을 때 이 컬럼이 null인지 체크하는 where절이 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;soft delete의 cascade도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️ 이력관리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 생성, 수정 이력을 관리하기 위한 컬럼으로 created, updated가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 데이터가 생성됐을때, 업데이트됐을 때의 시간을 timestamp로 기록해야 하는데 이것도 typeorm의 데코레이터를 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@CreateDateColumn()&lt;br /&gt;@UpdateDateColumn()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️ 추상클래스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 테이블에 soft delete를 포함한 이력관리를 하려고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 모든 테이블에 pk로 auto increse되는 id값을 주려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 엔티티를 정의할때마다 id, created, updated, deleted컬럼를 반복해서 넣어줘야 하는데 이럴때 추상클래스를 활용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1669028549618&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { CreateDateColumn, DeleteDateColumn, PrimaryGeneratedColumn, UpdateDateColumn } from &quot;typeorm&quot;;
// @Entity 데코레이터가 없으면 테이블이 생성되지 않는다
export abstract class Common {
    @PrimaryGeneratedColumn()
    id: number;

    @CreateDateColumn()
    created: Date; // 생성날짜

    @UpdateDateColumn()
    updated: Date; // 마지막 업데이트 날짜

    @DeleteDateColumn()
    deleted: Date; // soft-delete된 날짜
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1669028682171&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Column, Entity } from &quot;typeorm&quot;;
import { Common } from &quot;./common.entity&quot;;

@Entity()
export class User extends Common { // Common 클래스를 상속해서 User에 필요한 다른 컬럼들을 추가한다.
  @Column({ unique: true })
  email: string;

  @Column()
  password: string;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column({ nullable: true }) // nullable의 기본값은 false이다.
  profileImageUrl: string;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm run start:dev 로 개발환경에서 서버를 켜고 show tables를 해보면(TypeOrmModuleOptions의 synchronize: true로 설정)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cI6gVq/btrRK09yJ0U/NpPaoTesYNLOkirWAZj3YK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cI6gVq/btrRK09yJ0U/NpPaoTesYNLOkirWAZj3YK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cI6gVq/btrRK09yJ0U/NpPaoTesYNLOkirWAZj3YK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcI6gVq%2FbtrRK09yJ0U%2FNpPaoTesYNLOkirWAZj3YK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;290&quot; height=&quot;182&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user테이블이 생성된 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SaT6q/btrRKKTimec/SrOi7VXLZXis3IuwQ84ctK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SaT6q/btrRKKTimec/SrOi7VXLZXis3IuwQ84ctK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SaT6q/btrRKKTimec/SrOi7VXLZXis3IuwQ84ctK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSaT6q%2FbtrRKKTimec%2FSrOi7VXLZXis3IuwQ84ctK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1001&quot; height=&quot;269&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도대로 잘 생성되었다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*몇몇 컬럼들이 쓸데없이 255자까지 공간을 차지하고있으니까 @Column에 옵션을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) @Column({&amp;nbsp;type:&amp;nbsp;&quot;varchar&quot;,&amp;nbsp;length:&amp;nbsp;50&amp;nbsp;})&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4NERi/btrRJpu8bsA/qPdxwlQLOp9PV5WUbXkgsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4NERi/btrRJpu8bsA/qPdxwlQLOp9PV5WUbXkgsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4NERi/btrRJpu8bsA/qPdxwlQLOp9PV5WUbXkgsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4NERi%2FbtrRJpu8bsA%2FqPdxwlQLOp9PV5WUbXkgsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;979&quot; height=&quot;258&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;258&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://orkhan.gitbook.io/typeorm/docs/entities&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://orkhan.gitbook.io/typeorm/docs/entities&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://typeorm.io/many-to-many-relations#soft-deleting-a-relationship-with-cascade&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://typeorm.io/many-to-many-relations#soft-deleting-a-relationship-with-cascade&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/62696628/how-can-i-create-columns-with-type-date-and-type-datetime-in-nestjs-with-typeorm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/62696628/how-can-i-create-columns-with-type-date-and-type-datetime-in-nestjs-with-typeorm&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://doug-martin.github.io/nestjs-query/docs/persistence/typeorm/soft-delete/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://doug-martin.github.io/nestjs-query/docs/persistence/typeorm/soft-delete/&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/143</guid>
      <comments>https://ginghambagle.tistory.com/143#entry143comment</comments>
      <pubDate>Mon, 21 Nov 2022 20:16:59 +0900</pubDate>
    </item>
    <item>
      <title>NestJS | @nestjs/config 패키지를 활용한 환경변수 관리 -&amp;gt; db연결</title>
      <link>https://ginghambagle.tistory.com/142</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;dotenv.config를 활용해서 NODE_ENV에 따라 각각 다른 db를 연결했던것을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@nestjs/config 패키지를 활용해서 ConfigModule을 동적 모듈로 사용하는 방법으로 변경하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️env파일 경로 설정하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ConfigModule.forRoot()에 옵션값을 넘겨주면 동적 모듈을 생성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1669005979862&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(method) ConfigModule.forRoot(options?: ConfigModuleOptions): DynamicModule&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQfOLt/btrRHCAuk6D/JGGJEgzBPI4iNfdBTrIrnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQfOLt/btrRHCAuk6D/JGGJEgzBPI4iNfdBTrIrnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQfOLt/btrRHCAuk6D/JGGJEgzBPI4iNfdBTrIrnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQfOLt%2FbtrRHCAuk6D%2FJGGJEgzBPI4iNfdBTrIrnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;491&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵션에는 이런 값들을 넣을 수 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;envFilePath에 env파일의 경로를 주면 해당 파일을 루트경로에 있는 .env대신 읽어서 환경변수를 구성한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mWBjg/btrRHBayzsJ/UxhhZ70rTWQ6JCkGPG5REk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mWBjg/btrRHBayzsJ/UxhhZ70rTWQ6JCkGPG5REk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mWBjg/btrRHBayzsJ/UxhhZ70rTWQ6JCkGPG5REk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmWBjg%2FbtrRHBayzsJ%2FUxhhZ70rTWQ6JCkGPG5REk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;166&quot; height=&quot;140&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경변수 파일들은 src/configs/envs에 넣어놨고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.devgenius.io/environment-variables-in-nest-js-b989bb0370bf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고사이트&lt;/a&gt;를 참고해서 NODE_ENV에 따라 다른 env파일의 경로를 리턴하고, 없으면 sample.env의 경로를 리턴하는 getEnvPath함수를 작성해서 envFilePath를 지정했다.&lt;/p&gt;
&lt;pre id=&quot;code_1669006922522&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Module({
  imports: [
    ConfigModule.forRoot({ 
      envFilePath: getEnvPath(`${__dirname}/configs/envs`), 
      isGlobal: true 
    })
  ],&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 isGlobal은 true로 설정해서 어디서든 ConfigService에 접근할 수 있게 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Nest가&amp;nbsp;제공하는&amp;nbsp;ConfigModule은&amp;nbsp;.env&amp;nbsp;파일에서&amp;nbsp;읽어온&amp;nbsp;환경변수&amp;nbsp;값을&amp;nbsp;가져오는&amp;nbsp;프로바이더인&amp;nbsp;ConfigService가&amp;nbsp;있습니다.&amp;nbsp;이를&amp;nbsp;원하는&amp;nbsp;컴포넌트에서&amp;nbsp;주입하여&amp;nbsp;사용하면&amp;nbsp;됩니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ConfigService를 활용해서 환경변수를 가져와 db를 연결하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️ db연결&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeOrmModule의 forRootAsync에는 TypeOrmModulesAsyncOptions형의 옵션을 줄 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1669008489164&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(method) TypeOrmModule.forRootAsync(options: TypeOrmModuleAsyncOptions): DynamicModule&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeOrmModulesAsyncOptions은&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAOheN/btrRDUPHAkJ/JkCIeIXxwoLcW4pUU8KsyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAOheN/btrRDUPHAkJ/JkCIeIXxwoLcW4pUU8KsyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAOheN/btrRDUPHAkJ/JkCIeIXxwoLcW4pUU8KsyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAOheN%2FbtrRDUPHAkJ%2FJkCIeIXxwoLcW4pUU8KsyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;670&quot; height=&quot;146&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생겼는데 그중 useClass에 들어가는 TypeOrmOptionsFactory는&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcMDxw/btrRMDrA09S/XBpq9DM368K8FnqdNktK50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcMDxw/btrRMDrA09S/XBpq9DM368K8FnqdNktK50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcMDxw/btrRMDrA09S/XBpq9DM368K8FnqdNktK50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcMDxw%2FbtrRMDrA09S%2FXBpq9DM368K8FnqdNktK50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;797&quot; height=&quot;58&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise&amp;lt;TypeOrmModuleOptions&amp;gt; | TypeOrmModuleOptions 를 리턴하는 createTypeOrmOptions를 가지고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;개발환경에 따라 다른 db를 연결하려면 &lt;/span&gt;환경변수값을 ConfigService로 가져오기 위해서 클래스로 만들어야 하는데&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 클래스로 TypeOrmModule을 설정하려면 forRootAsync 메서드를 사용하고 useClass옵션에 해당 클래스를 주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 그 클래스는 TypeOrmOptionsFactory 타입이어야 하고, TypeOrmModuleOptions를 리턴하는 createTypeOrmOptions를 가지고있어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1669009869632&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// typeorm.config.ts
import { Injectable } from &quot;@nestjs/common&quot;;
import { ConfigService } from &quot;@nestjs/config&quot;;
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from &quot;@nestjs/typeorm&quot;;

@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {

    constructor(private configService: ConfigService) {}

    createTypeOrmOptions(): TypeOrmModuleOptions {
      return {
        type: 'mysql',
        host: this.configService.get('DATABASE_HOST'),
        port: Number(this.configService.get('DATABASE_PORT')),
        username: this.configService.get('DATABASE_USERNAME'),
        password: this.configService.get('DATABASE_PASSWORD'),
        database: this.configService.get('DATABASE_NAME'),
        entities: [__dirname + '/../**/*.entity.{js,ts}'],
        synchronize: Boolean(this.configService.get('DATABASE_SYNCHRONIZE'))
      };
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1669009909503&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app.module.ts
...
@Module({
  imports: [
    ConfigModule.forRoot({ 
      envFilePath: getEnvPath(`${__dirname}/configs/envs`), 
      isGlobal: true 
    }),
    TypeOrmModule.forRootAsync({
      useClass: TypeOrmConfigService
    })
  ],
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이렇게 작성해서 연결완료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(참고자료 보고 먼저 만들고 후학습!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.to/raphael_haecker/nestjs-and-typeorm-database-configuration-15ob&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dev.to/raphael_haecker/nestjs-and-typeorm-database-configuration-15ob&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.devgenius.io/environment-variables-in-nest-js-b989bb0370bf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.devgenius.io/environment-variables-in-nest-js-b989bb0370bf&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wikidocs.net/158584&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://wikidocs.net/158584&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/142</guid>
      <comments>https://ginghambagle.tistory.com/142#entry142comment</comments>
      <pubDate>Mon, 21 Nov 2022 14:56:57 +0900</pubDate>
    </item>
    <item>
      <title>NestJS | production/development환경 각각 다른 DB 사용하기(dotenv)</title>
      <link>https://ginghambagle.tistory.com/141</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️ production/development 환경 구분하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 하면서 이것저것 테스트를 해보게될텐데 배포해서 출시된 프로덕트와 연결된 디비에다가 테스트를 막 하면 안되겠쥬..?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 배포환경/개발환경일때 따라서 각각 다른 db를 사용해야 하는데 환경변수 관리 라이브러리 dotenv를 이용해서 하는 방법이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경에 따라 서로 다른 .env파일을 읽도록 하는것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node.js는 NODE_ENV라는 환경변수를 활용하여 서버의 환경을 구분한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json 파일을 수정하여 npm run start:dev 명령이 수행될 때 NODE_ENV가 development로 설정되도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1668857512510&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// package.json
&quot;scripts&quot;: {
    ...
    &quot;start:dev&quot;: &quot;NODE_ENV=development nest start --watch&quot;,
    ...
  },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 env라는 폴더를 만들어 개발환경에서 사용할 환경변수를.development.env에, 프로덕션환경에서 사용할 환경변수를 .production.env에 저장해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;161&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eycDgI/btrRzGp9ufS/7rRkkWzrJ7E6ZR3z7kZz00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eycDgI/btrRzGp9ufS/7rRkkWzrJ7E6ZR3z7kZz00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eycDgI/btrRzGp9ufS/7rRkkWzrJ7E6ZR3z7kZz00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeycDgI%2FbtrRzGp9ufS%2F7rRkkWzrJ7E6ZR3z7kZz00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;161&quot; height=&quot;68&quot; data-origin-width=&quot;161&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O6kuZ/btrRAL5lPJf/KS9I1JjAt80owauwirL4w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O6kuZ/btrRAL5lPJf/KS9I1JjAt80owauwirL4w1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O6kuZ/btrRAL5lPJf/KS9I1JjAt80owauwirL4w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO6kuZ%2FbtrRAL5lPJf%2FKS9I1JjAt80owauwirL4w1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;447&quot; height=&quot;89&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;89&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 테스트를 위해 CURRENT_MODE에 prod, dev를 저장해놨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 main.ts에 아래와 같은 코드를 추가해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1668857807699&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// main.ts
import * as dotenv from 'dotenv';
import * as path from 'path';

dotenv.config({
  path: path.resolve(
    (process.env.NODE_ENV === 'development') ? 'env/.development.env' : 'env/.production.env'
  )
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NODE_ENV가 development일 때는 .development.env, 아닐때는 .production.env파일을 읽도록 설정해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668860571261&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.SERVER_PORT);
  console.log(process.env.CURRENT_MODE);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트하기위해 콘솔에 CURRENT_MODE를 출력하게 하고 실행해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; npm run start&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;131&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmRLko/btrRBfrDCCk/s0rmlfebwqc9dT3DyEvWM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmRLko/btrRBfrDCCk/s0rmlfebwqc9dT3DyEvWM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmRLko/btrRBfrDCCk/s0rmlfebwqc9dT3DyEvWM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmRLko%2FbtrRBfrDCCk%2Fs0rmlfebwqc9dT3DyEvWM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;131&quot; height=&quot;72&quot; data-origin-width=&quot;131&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; npm run start:dev&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;63&quot; data-origin-height=&quot;55&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beXW6n/btrRBKkA2oL/PhvG9kN1WR7NPq0SItTdk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beXW6n/btrRBKkA2oL/PhvG9kN1WR7NPq0SItTdk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beXW6n/btrRBKkA2oL/PhvG9kN1WR7NPq0SItTdk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeXW6n%2FbtrRBKkA2oL%2FPhvG9kN1WR7NPq0SItTdk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;63&quot; height=&quot;55&quot; data-origin-width=&quot;63&quot; data-origin-height=&quot;55&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경에 맞게 다른 env파일을 잘 읽는걸 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️ DB 연결하기&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3PsZw/btrRBKLGpsK/gzg6tV0fbqvKlQwaWjcqTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3PsZw/btrRBKLGpsK/gzg6tV0fbqvKlQwaWjcqTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3PsZw/btrRBKLGpsK/gzg6tV0fbqvKlQwaWjcqTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3PsZw%2FbtrRBKLGpsK%2Fgzg6tV0fbqvKlQwaWjcqTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;658&quot; height=&quot;222&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5PpR2/btrRzf0GaqU/iw2xXU29rkN6Dri7W6sMs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5PpR2/btrRzf0GaqU/iw2xXU29rkN6Dri7W6sMs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5PpR2/btrRzf0GaqU/iw2xXU29rkN6Dri7W6sMs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5PpR2%2FbtrRzf0GaqU%2Fiw2xXU29rkN6Dri7W6sMs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;278&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 configs/typeorm.config.ts에 typeORMConfig를 작성하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app.module.ts에서 임포트했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lSVf6/btrRBeTNlG3/VPWHxsLIFK5Q4gq8QmlCGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lSVf6/btrRBeTNlG3/VPWHxsLIFK5Q4gq8QmlCGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lSVf6/btrRBeTNlG3/VPWHxsLIFK5Q4gq8QmlCGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlSVf6%2FbtrRBeTNlG3%2FVPWHxsLIFK5Q4gq8QmlCGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;354&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main.ts는 이렇게 작성해놨는데&lt;/p&gt;
&lt;pre id=&quot;code_1668861203736&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Nest] 66182  - 2022. 11. 19. 오후 9:32:49   ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)...
Error: Access denied for user ''@'localhost' (using password: YES)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 이런 에러가 났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 typeORMConfig를 환경변수를 불러오지 않고 각각 넣어줘봤는데 잘 돌아갔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/unv3v/btrRAi3utUd/TXcUi9v2IKGxcokEy6RkTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/unv3v/btrRAi3utUd/TXcUi9v2IKGxcokEy6RkTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/unv3v/btrRAi3utUd/TXcUi9v2IKGxcokEy6RkTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Funv3v%2FbtrRAi3utUd%2FTXcUi9v2IKGxcokEy6RkTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;233&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 환경변수를 못읽는건가? 해서 전체 환경변수도 콘솔에 찍어봤는데 제대로 나왔다......ㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 옵션을 한줄한줄 환경변수를 불러오도록 바꾸면서 계속 실행해봤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PvGiL/btrRALRSdr5/1738A2m8F3GFPC2b9hYEIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PvGiL/btrRALRSdr5/1738A2m8F3GFPC2b9hYEIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PvGiL/btrRALRSdr5/1738A2m8F3GFPC2b9hYEIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPvGiL%2FbtrRALRSdr5%2F1738A2m8F3GFPC2b9hYEIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;449&quot; height=&quot;221&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로......&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;port까지는 정상적으로 돌아가는데&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #6766b3;&quot;&gt;username: process.env.DATABASE_USERNAME&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 하는 순간 같은 에러가 났다ㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;host port는 잘 불러오면서 왜 username하고 password만???&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;username하고 password만 못읽어오는 이유는.............?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xmrng/btrRDUAd9R2/CIzDBjrI5tZaUpvJXx4x5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xmrng/btrRDUAd9R2/CIzDBjrI5tZaUpvJXx4x5k/img.png&quot; data-alt=&quot;고통의흔저규&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xmrng/btrRDUAd9R2/CIzDBjrI5tZaUpvJXx4x5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxmrng%2FbtrRDUAd9R2%2FCIzDBjrI5tZaUpvJXx4x5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;296&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;고통의흔저규&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무데서도 답을 찾을수가 없었다ㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;겹치는 로컬 변수가 있나 해서 다시 찍어봐도 정상적으로 잘 나오는데 왜 접속실패일까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그러다가 에러메세지에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;''@'localhost' 이부분이 눈에 들어와서&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668861935043&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;username: 'root',
password: process.env.DATABASE_PASSWORD,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 이렇게 수정했더니 에러메세지가&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668861970849&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error: Access denied for user 'root'@'localhost' (using password: YES)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 바뀌었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;못읽는거네 근데왜............?????????&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 아 설마설마............;;;;;;;;;;;;;;;ㅠㅠㅠㅠㅠㅠㅠㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 main.ts의 코드를 바꿔봤다 이렇게 환경변수 설정을 위로...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;363&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOBkc6/btrREVlp5NW/7VWX4jnZBZi0f6pDT3gO91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOBkc6/btrREVlp5NW/7VWX4jnZBZi0f6pDT3gO91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOBkc6/btrREVlp5NW/7VWX4jnZBZi0f6pDT3gO91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOBkc6%2FbtrREVlp5NW%2F7VWX4jnZBZi0f6pDT3gO91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;432&quot; height=&quot;363&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그랬더니 정상동작했당..ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppModule 안에 typeORMConfig가 있으니까 env파일을 먼저 읽고 AppModule을 불러와야하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서가 거꾸로돼서 환경변수가 안읽혔던것같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 대체왜.............&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DATABASE_HOST랑 DATABASE_PORT랑은 읽고 username부터 못읽은걸까???????&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 는 host랑 port를 읽은게 아니었다~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/mysqljs/mysql#connection-options&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/mysqljs/mysql#connection-options&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 들어가서 보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;host의 기본값은 localhost,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;port의 기본값은 3306으로 설정돼있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 host, port에 환경변수를 넣었을때 아무것도 안들어가서 기본값으로 설정되어 정상적으로 연결됐던것!ㅠ&lt;s&gt;(내 2시간 돌려줘)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 이렇게 해서 개발/프로덕션 환경에 따라 다른 디비에 연결되도록 설정을 했다~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wikidocs.net/158579&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://wikidocs.net/158579&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/141</guid>
      <comments>https://ginghambagle.tistory.com/141#entry141comment</comments>
      <pubDate>Sat, 19 Nov 2022 22:06:39 +0900</pubDate>
    </item>
    <item>
      <title>NestJS | 패키지 버전 지정해서 세팅하기</title>
      <link>https://ginghambagle.tistory.com/140</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;글로벌환경과 다른 nest 버전으로 프로젝트 시작하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 컴터에 깔린 nestjs 버전은 9.1.4이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;46&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsVIoc/btrRDVMw3VK/4In4UkX8U2EulyDbCdxshk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsVIoc/btrRDVMw3VK/4In4UkX8U2EulyDbCdxshk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsVIoc/btrRDVMw3VK/4In4UkX8U2EulyDbCdxshk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsVIoc%2FbtrRDVMw3VK%2F4In4UkX8U2EulyDbCdxshk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;171&quot; height=&quot;46&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;46&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 그냥 nest new 프로젝트명 명령어로 프로젝트를 시작하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 ^9.0.0으로 깔리게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UV5xC/btrRzkHvY0P/VEVvwVwAHrpRfYDbvIfZv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UV5xC/btrRzkHvY0P/VEVvwVwAHrpRfYDbvIfZv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UV5xC/btrRzkHvY0P/VEVvwVwAHrpRfYDbvIfZv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUV5xC%2FbtrRzkHvY0P%2FVEVvwVwAHrpRfYDbvIfZv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;264&quot; height=&quot;80&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 8.2.x버전의 프로젝트가 필요한 상황이라 아래 명령어로 프로젝트를 시작했다.&lt;/p&gt;
&lt;pre id=&quot;code_1668840953017&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx @nestjs/cli@버전 new 프로젝트명&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npx @nestjs/cli@^8.2 new 프로젝트명&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7RS9C/btrRBeF5uFC/SyULsy6iPKYkAKtOYxyUt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7RS9C/btrRBeF5uFC/SyULsy6iPKYkAKtOYxyUt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7RS9C/btrRBeF5uFC/SyULsy6iPKYkAKtOYxyUt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7RS9C%2FbtrRBeF5uFC%2FSyULsy6iPKYkAKtOYxyUt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;76&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이렇게 8.0.0이상 버전으로 깔리게 된다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8.2.0이 아니라 8.0.0이라서 package.json에서 직접 ^8.2.0으로 변경 후 npm install을 해봤는데 에러가 났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;^8.0.0은 8이상이니까 8.2에서도 돌아가긴 할테니까 패쓰....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9.1.4버전에서 nest new를 해도 ^9.0.0으로 깔리는걸 보니 원래 0.0으로 끊는건가봉가?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;typeorm 0.2.41 설치&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;db는 mysql을 사용하고 typeorm을 사용할건데 typeorm 버전은 0.2.41이 필요하다&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;$ npm install @nestjs/typeorm typeorm@0.2.41 mysql2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 @nestjs/typeorm이 먼저 최신 버전으로 깔려서 typeorm 0.2.41이 깔리지 않고 에러가 난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 먼저 typeorm@0.2.41을 깔고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm install @nestjs/typeorm을 하면 또 최신버전으로 까는건지 에러가 난다&lt;s&gt;(npm이 원래 깔려있는 패키지들 버전 보고 알아서 호환되는 버전으로 깔아줄줄 알았다ㅠ)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &quot;typeorm 0.2.41 nestjs&quot;로 검색을 해서 나온 &lt;a href=&quot;https://wikidocs.net/158615&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고페이지&lt;/a&gt;에서 보고 @nestjs/typeorm은 8.0.2 버전으로 지정해서 설치했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b80DBN/btrRANaRjUR/seEFNhlzOIdCi2CwKYkFS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b80DBN/btrRANaRjUR/seEFNhlzOIdCi2CwKYkFS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b80DBN/btrRANaRjUR/seEFNhlzOIdCi2CwKYkFS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb80DBN%2FbtrRANaRjUR%2FseEFNhlzOIdCi2CwKYkFS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;132&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <category>nestjs</category>
      <category>프로젝트</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/140</guid>
      <comments>https://ginghambagle.tistory.com/140#entry140comment</comments>
      <pubDate>Sat, 19 Nov 2022 16:29:48 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 | 인덱스란?</title>
      <link>https://ginghambagle.tistory.com/139</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 대한 대다수 요청은 전체 데이터 중 극히 일부분만을 필요로 한다. 그런데 레코드를 검색하기 위한 보조 기술이 따로 없다면 DBMS는 요청에 만족하는 데이터를 검색하기 위해 존재하는 레코드를 처음부터 끝까지 순차적으로 검사하게 되는 비효율적인 결과를 낳는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인덱싱 기법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS에서 신속한 데이터 검색을 지원하기 위한 보조 기술&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색키를 이용해서 해당 데이터가 저장된 블럭을 빠르게 파악해서 검색 결과를 생성해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색키: 파일에서 레코드를 찾는데 사용되는 컬럼(들).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인덱스 기반 검색&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 어떤 레코드를 검색하면 DBMS는 찾을레코드 블럭을 바로 메모리에 올리는 것이 아니라 인덱스 블럭을 올린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어차피 올리는거 그냥 올리면 되는거 아닌가? 괜히 한단계 더 추가된거 아닌가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 인덱스블럭은 실제 레코드 블럭보다 사이즈가 작기 때문에 한번에 많은 양을 메모리에 올릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 인덱스가 없으면 데이터 일부를 메모리에 올리고-&amp;gt;아니네? 다음블럭-&amp;gt; 아니네?다음블럭 이렇게 하나하나 탐색하게 되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 인덱스만 있는 블럭으로 한번에 많은 범위를 탐색할 수 있고 이를 통해 찾을 레코드의 위치를 빠르게 알아낼 수 있고 위치를 알기 때문에 해당 위치에 바로 접근해 데이터를 찾을 수 있기 때문에 훨씬 성능이 좋아진다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>데이터베이스</category>
      <category>인덱스</category>
      <category>인덱싱</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/139</guid>
      <comments>https://ginghambagle.tistory.com/139#entry139comment</comments>
      <pubDate>Thu, 10 Nov 2022 15:02:39 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 | 트랜잭션 동시성 제어 - 락 기반 규약</title>
      <link>https://ginghambagle.tistory.com/138</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;여러 트랜잭션이 동시에 같은 데이터에 대한 읽기나 갱신 작업을 할때 데이터의 무결성이 훼손될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계좌 B 잔액: 0원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 1: A -&amp;gt; B 1000원 입금&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 2: ATM에서 B에 1000원 입금&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업완료 후 계좌 B의 잔액은 2000원이 되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 두 트랜잭션이 동시에 실행될 경우&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 28.6047%; height: 114px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;t1&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;t2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;READ(A)&lt;br /&gt;A := A - 1000&lt;br /&gt;WRITE(A)&lt;br /&gt;READ(B)&lt;br /&gt;B := B +1000&lt;br /&gt;WRITE(B)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;br /&gt;READ(B)&lt;br /&gt;B := B +1000&lt;br /&gt;WRITE(B)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 트랜잭션 모두 B의 잔액이 0원일 때 읽은 후 1000원을 더해서 데이터를 갱신하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 B의 잔액이 2000원이 아니라 1000원이 되는 상황이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;동시성 제어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 사이 연산 순서를 제어해서 데이터의 무결성을 유지하면서도 동시 실행하는 트랜잭션의 수를 최대한으로 증가시키기 위한 기법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;락 기반 규약은 동시성 제어 기법 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;락 기반 규약&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터에 연산 적용 전 트랜잭션이 락을 획득하고 연산 종료 후 락을 다시 반납하도록 하는 규약&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;락의 종류&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;공유 락(shared lock: S)&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 작업만 할 때 사용. 공유 락끼리는 양립 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 지금 이 데이터 읽을거니까 아무도 갱신하지마 그대신 다른애들이 와서 읽기만 하는건 상관없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;배타 락(exclusive lock: X)&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽고 쓰기 작업을 할 때 사용. 다른 락과 양립 불가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 이 데이터 읽고 갱신도 할거니까 작업 끝날때까지 아무도 읽지도 마&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;분산락&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가&amp;nbsp;여러&amp;nbsp;대인&amp;nbsp;상황에서&amp;nbsp;동일한&amp;nbsp;데이터에&amp;nbsp;대한&amp;nbsp;동기화를&amp;nbsp;보장하기&amp;nbsp;위해&amp;nbsp;사용하는것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 여러대인 경우 여러 서버로 API가 분산 호출 된다.&lt;br /&gt;서버들간에 동기화된 처리가 필요하고, 여러 서버에 공통된 락을 적용해야 하기 위해 사용한다.&amp;nbsp;&lt;br /&gt;분산 락은 db 등 공통된 데이터 저장소를 이용해 자원이 사용중인지 확인하기 때문에 전체 서버에 동기화된 처리가 가능 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;교착상태&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;t1: B -&amp;gt; A 로 1000원 입금&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;t2: A + B 계좌의 합을 보여줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션들이 작업완료후 락을 반납하는 경우 두 트랜잭션이 동시에 수행되면&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.814%; height: 464px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;t1&lt;/td&gt;
&lt;td style=&quot;width: 72.1709%;&quot;&gt;t2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;LX(B) - B에대한 배타락 획득&lt;br /&gt;READ(B)&lt;br /&gt;B := B - 1000&lt;br /&gt;WRITE(B)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;LX(A) - A에대한 배타락 요청...획득안됨. t1이 A에 공유락을 걸어서..&lt;br /&gt;...&lt;br /&gt;&lt;s&gt;READ(A)&lt;/s&gt;&lt;br /&gt;&lt;s&gt;A := A +1000&lt;/s&gt;&lt;br /&gt;&lt;s&gt;WRITE(A)&lt;/s&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.1709%;&quot;&gt;LS(A) - A에대한 공유락 획득&lt;br /&gt;READ(A)&lt;br /&gt;LS(B) - B에대한 공유락 요청...획득안됨. t1이 B에 배타락을 걸어서&lt;br /&gt;...&lt;br /&gt;&lt;s&gt;READ(B)&lt;/s&gt;&lt;br /&gt;&lt;s&gt;DISPLAY(A+B)&lt;/s&gt;&lt;br /&gt;&lt;s&gt;UN(A)&lt;/s&gt;&lt;br /&gt;&lt;s&gt;UN(B)&lt;/s&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 서로 맞물려서 영원히 멈춰있게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상태를 교착상태라고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태는 한 트랜잭션을 롤백해서 해결할 수 있다. 트랜잭션이 롤백되면 해당 트랜잭션이 갖고있던 락은 모두 반납된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://soyeon207.github.io/db/2021/08/29/distributed-lock.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://soyeon207.github.io/db/2021/08/29/distributed-lock.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>데이터베이스</category>
      <category>분산락</category>
      <category>트랜잭션</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/138</guid>
      <comments>https://ginghambagle.tistory.com/138#entry138comment</comments>
      <pubDate>Thu, 3 Nov 2022 13:17:24 +0900</pubDate>
    </item>
    <item>
      <title>git &amp;amp; github | 레포지토리 복제하기(clone --mirror 에러)</title>
      <link>https://ginghambagle.tistory.com/137</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;팀과제 리팩토링을 위해 개인레포로 복제했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666607271905&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git clone --mirror {old_repository_url}
$ cd {프로젝트명}.git
$ git remote set-url --push origin {new_repository_url}
$ git push --mirror&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 마지막 명령에서 아래처럼 에러가 났다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;669&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4qEel/btrPsYln7QN/FyeBlJKg73PsHZjqCMjZrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4qEel/btrPsYln7QN/FyeBlJKg73PsHZjqCMjZrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4qEel/btrPsYln7QN/FyeBlJKg73PsHZjqCMjZrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4qEel%2FbtrPsYln7QN%2FFyeBlJKg73PsHZjqCMjZrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;831&quot; height=&quot;669&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;669&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666607405277&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; ! [remote rejected] refs/pull/1/head -&amp;gt; refs/pull/1/head (deny updating a hidden ref)
 ! [remote rejected] refs/pull/10/head -&amp;gt; refs/pull/10/head (deny updating a hidden ref)
 ! [remote rejected] refs/pull/11/head -&amp;gt; refs/pull/11/head (deny updating a hidden ref)
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색을 해보니 깃허브는 pull요청을 특별한 git ref로 관리하는데 그래서 미러링을 하면 원래 레포의 모든 브랜치와 기록들이 복제되면서 깃허브에서 pull한 기록까지 가져와버린다고 한다. 그래서 레포지토리 용량이 두 배로 커질 수 있고 어떤 pull request들은 오래된 브랜치에서 pull했기 때문에 그대로 가져오면 충돌이 일어날 수도 있다. 그래서 그런 상황을 막기 위해 에러를 발생시키는것같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;에러 없이 레포지토리 복제하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bare 옵션으로 원래 레포를 clone하고 mirror 옵션으로 새로운 레포에 push하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666608551545&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git clone --bare https://github.com/exampleuser/old-repository.git
$ cd old-repository
$ git push --mirror https://github.com/exampleuser/new-repository.git&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://christoph.ruegg.name/blog/git-howto-mirror-a-github-repository-without-pull-refs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://christoph.ruegg.name/blog/git-howto-mirror-a-github-repository-without-pull-refs.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/34265266/remote-rejected-errors-after-mirroring-a-git-repository&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/34265266/remote-rejected-errors-after-mirroring-a-git-repository&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://projooni.tistory.com/entry/%EA%B8%B0%EC%A1%B4-Git-Repository%EB%A5%BC-%EB%B3%B5%EC%82%AC%ED%95%98%EC%97%AC-%EC%83%88%EB%A1%9C%EC%9A%B4-Repository-%EB%A7%8C%EB%93%A4%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://projooni.tistory.com/entry/%EA%B8%B0%EC%A1%B4-Git-Repository%EB%A5%BC-%EB%B3%B5%EC%82%AC%ED%95%98%EC%97%AC-%EC%83%88%EB%A1%9C%EC%9A%B4-Repository-%EB%A7%8C%EB%93%A4%EA%B8%B0&lt;/a&gt;&lt;/p&gt;</description>
      <category>git &amp;amp; GitHub</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/137</guid>
      <comments>https://ginghambagle.tistory.com/137#entry137comment</comments>
      <pubDate>Mon, 24 Oct 2022 19:51:20 +0900</pubDate>
    </item>
    <item>
      <title>프리온보딩 | 2차과제 - 3: auth미들웨어, Swagger</title>
      <link>https://ginghambagle.tistory.com/136</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;✨ 로그인 적용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인기능이 머지되기 전이라서 임의로 is_admin과 province_id를 코드에 적어놓고 테스트를 했었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미들웨어가 완성돼서 적용시켰다.&lt;/p&gt;
&lt;pre id=&quot;code_1665380848082&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// hospitalRouter.js
const { authMiddleware } = require(&quot;../middlewares/auth&quot;);
...

router.get(&quot;&quot;, authMiddleware, errorHandler(hospitalController.getHospitalDataController));
router.get(&quot;/download&quot;, authMiddleware, errorHandler(hospitalController.downloadHospitalDataController));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;authMiddleware에는 요청 headers의 Authorization키로 들어온 토큰을 빼서 나온 유저의 정보를 req.user에 저장하는 코드가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그걸 라우터에서 컨트롤러 전단계에 넣어주면 마치 파이썬 로그인 데코레이터처럼 컨트롤러로 가기 전에 authMiddleware에 들러서 토큰을 분석해서 인가처리를 할 수 있게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1665381230856&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const getHospitalDataController = async (req, res) =&amp;gt; {
  // //====페이로드예시===========
  // const payLoad = {
  //   id: 1,
  //   is_admin: 1,
  //   province_id: null,
  // }
  // //=======================
  // const {is_admin, province_id} = payLoad;
  const {userId, isAdmin, provinceId } = req.user;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 임의로 사용하던 코드(주석처리된부분)를 지우고 미들웨어를 적용해서 코드를 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✨ Swagger 적용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 과제에는 API문서를 swagger를 이용해서 작성해야 한다는 조건이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세팅&lt;/p&gt;
&lt;pre id=&quot;code_1665384113847&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// swagger/swagger.js
const swaggerUi = require(&quot;swagger-ui-express&quot;);
const swaggereJsdoc = require(&quot;swagger-jsdoc&quot;);

const options = {
  swaggerDefinition: {
    openapi: &quot;3.0.n&quot;,
    info: {
      version: &quot;1.0.0&quot;,
      title: &quot;Haii&quot;,
      description: &quot;Admin용 데이터 관리 프로그램 만들기&quot;,
    },
    servers: [
      {
        url: &quot;http://localhost:8000&quot;,
      },
    ],
    components: {
      securitySchemes: {
        Authorization: {
          type: &quot;http&quot;,
          scheme: &quot;bearer&quot;,
          bearerFormat: &quot;JWT&quot;,
          value: &quot;bearer &amp;lt;JWT token here&amp;gt;&quot;,
        },
      },
    },
  },
  apis: [&quot;./swagger/*/*.js&quot;], // swagger폴더안에 기능에 따라 폴더를 나눠놓고 그 안에 작성할 모든 파일들을 api문서로 이용
};

const specs = swaggereJsdoc(options);

module.exports = {
  swaggerUi,
  specs,
};

// app.js
const createApp = () =&amp;gt; {
  ...
  const { swaggerUi, specs } = require(&quot;./swagger/swagger&quot;);
  app.use(&quot;/api-docs&quot;, swaggerUi.serve, swaggerUi.setup(specs));
  return app;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세팅을 한 후엔..노가다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 url, 바디에 들어갈 데이터 등 요청방식과 응답방식을 모두 직접 적어줘야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1665384518128&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// swagger/hospital/hospitalList.js

/**
* @swagger
*
* /hospital:
*  get:
*    //요청에대한정보
*
*    responses:
*    //응답정보
*      400:
*        //400응답의 정보
*      200:
*        //200응답의 정보
*                 
 */&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 형식으로 적어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;요청 파라미터 정의&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://swagger.io/docs/specification/describing-parameters/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스웨거 공식문서&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 헤더의 토큰&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 다른 코드를 찾아보다가&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1665386097847&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
* /hospital:
*  get:
*    security:
*      - Authorization: []
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 코드를 발견하고 이게 headers의 Authorization키에 담긴 토큰 확인하는 방법인줄 알고 복사해서 썼는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 내가 만든 API에 요청할때 토큰이 필요하다는게 아니고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해당 API문서를 확인하려면 Authorization이 필요하다는 뜻&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 작성하고 명세서를 확인하면 제목에 열려있는 자물쇠 아이콘이 뜬다(인가가 필요하다곤 했는데 [ ]빈칸으로 둬서 열린 자물쇠로 나오고 누르면 열리는것같다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 목적인 header-Authorization키에 담긴 토큰을 확인하는건 아래 코드&lt;/p&gt;
&lt;pre id=&quot;code_1665385929700&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
* /hospital:
*  get:
*    summary: &quot;치매센터 리스트 검색 &amp;amp; 조회 기능&quot;
*    parameters:
*       - in: header           // 어디에 담겨오는지: 헤더
*         name: Authorization  // 키: Authorization
*         description: &quot;인가에 필요한 토큰&quot;
*         required: true       // 필수
*         schema:
*          type: string        // 데이터타입
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  쿼리파라미터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건검색을 위한 쿼리 파라미터도 문서를 보고 아래처럼 작성했다.&lt;/p&gt;
&lt;pre id=&quot;code_1665386541632&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
*       - in: query
*         name: name
*         schema:
*          type: string
*         description: 치매센터명 검색(단어 부분검색)
*       - in: query
*         name: representative
*         schema:
*           type: string
*         description: 운영기관대표자명 검색(단어 부분검색)
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 get메서드 요청 기능만 맡아서 요청 바디를 기술해줄 필요는 없었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바디에 대한 설명은 아래처럼 적어주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1665386847076&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
*   /users:
 *     post:
...
 *       requestBody:
 ...&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;응답&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  http 상태코드가 같은데 다른 응답일때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1665387215293&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
*
*      200:
*        description: 정상 요청일 경우 치매센터 리스트 엑셀파일 다운로드
*        content:
*          application/json:
*            schema:
*              type: object
*              properties:
*                  status:
*                    type: number
*                    example: 200
*                  message:
*                    type: string
*                    example: &quot;success&quot;
*
*       400:
*         description: 관리자에게 담당지역이 있을때
*         content:
*           application/json:
*             schema:
*               type: object
*               properties:
*                 message:
*                   type: string
*                   example: &quot;admin cannot have province_id&quot;
*       400:
*         description: 관리자가 아닌데 담당지역이 없을때
*         content:
*         ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답도 이렇게 적어주면 되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼&amp;nbsp;400이라는 응답이 두개면 에러가 난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(근데 이제보니까 403응답을 줬어야 했던것같다 권한이 없는거니까! 고치고싶은데 제출한 다음이라 못건드리겠다.....)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 검색을 해서 &lt;a href=&quot;https://stackoverflow.com/questions/47447403/how-to-define-different-responses-for-same-http-status-code-in-openapi-swagger&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스택오버플로우&lt;/a&gt;에서 방법을 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;schema에 oneOf옵션을 주는것!&lt;/p&gt;
&lt;pre id=&quot;code_1665387908057&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;*    responses:
*      400:
*        description: 관리자에게 담당지역이 있을때 / 관리자가 아닌데 담당지역이 없을때
*        content:
*          application/json:
*            schema:
*              oneOf:
*                - $ref: '#/components/schemas/adminwprovince'
*                - $ref: '#/components/schemas/noadminwoprovince'
*              examples:
*                adminwprovince:
*                  summary: 관리자에게 담당지역이 있을때
*                  value:
*                    status: 400
*                    message: &quot;admin cannot have province_id&quot;
*                noadminwoprovince:
*                  summary: 관리자가 아닌데 담당지역이 없을때
*                  value:
*                    status: 400
*                    message: &quot;province_id not provided&quot;
*
...
*
* components:
*   schemas:
*     adminwprovince:
*       type: object
*       properties:
*         status:
*           type: number
*           example: 400
*         message:
*           type: string
*           example: &quot;admin cannot have province_id&quot;
*     noadminwoprovince:
*       type: object
*       properties:
*         status:
*           type: number
*           example: 400
*         message:
*           type: string
*           example: &quot;province_id not provided&quot;
*                 
 */&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들고 명세서를 열면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/INNzd/btrN9laYYgJ/wKYDKccrKysQEYlU2qYDF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/INNzd/btrN9laYYgJ/wKYDKccrKysQEYlU2qYDF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/INNzd/btrN9laYYgJ/wKYDKccrKysQEYlU2qYDF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FINNzd%2FbtrN9laYYgJ%2FwKYDKccrKysQEYlU2qYDF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;847&quot; height=&quot;254&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 예시 하나만 나오고 옆에 &quot;Schema&quot; 를 누르면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZSnaS/btrN9rClDTk/3TtKN17ahtePKH7mXHMsNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZSnaS/btrN9rClDTk/3TtKN17ahtePKH7mXHMsNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZSnaS/btrN9rClDTk/3TtKN17ahtePKH7mXHMsNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZSnaS%2FbtrN9rClDTk%2F3TtKN17ahtePKH7mXHMsNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;795&quot; height=&quot;430&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 모든 예시를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;나머지 참고했던 링크&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/belgif/rest-guide/issues/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/belgif/rest-guide/issues/79&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://swagger.io/docs/specification/data-models/data-types/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://swagger.io/docs/specification/data-models/data-types/&lt;/a&gt;&lt;/p&gt;</description>
      <category>wecode</category>
      <category>과제</category>
      <category>백엔드</category>
      <category>원티드</category>
      <category>코스</category>
      <category>프리온보딩</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/136</guid>
      <comments>https://ginghambagle.tistory.com/136#entry136comment</comments>
      <pubDate>Mon, 10 Oct 2022 16:55:14 +0900</pubDate>
    </item>
    <item>
      <title>프리온보딩 | 2차과제 - 2: 엑셀다운로드, 검색기능</title>
      <link>https://ginghambagle.tistory.com/135</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;엑셀다운로드기능&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 지역별 담당자는 해당 지역에 대한 데이터만을 조회하여 엑셀 파일로 다운로드받을 수 있어야 하며...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라고 나와있는데 조회-다운로드가 한기능인가 싶었는데 조회만 하고, 다운로드 하고싶을때 다운로드 하는게 맞는것같아서 따로 나눠서 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회 url은 '/hospital'이고 다운로드는 '/hospital/download'로 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회한 데이터랑 같은 데이터를 엑셀로 받는거기 때문에 컨트롤러만 나눠서 조회할때랑 같은 서비스로 보냈다.&lt;/p&gt;
&lt;pre id=&quot;code_1665294412660&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// controllers/hospitalController.js
// 조회기능
const getHospitalDataController = async (req, res) =&amp;gt; {
  ...

  const hospitalData = await hospitalService.getHospitalDataService(is_admin, province_id, reqQuery);
  res.status(200).json({data: hospitalData});
};
// 다운로드기능
const downloadHospitalDataController = async (req, res) =&amp;gt; {
  ...

  const hospitalData = await hospitalService.getHospitalDataService(is_admin, province_id, reqQuery);
  await xlsxWriter.writeExcelFile(hospitalData);
  res.status(200).json({message: &quot;success&quot;});
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 조회는 받은 데이터를 응답으로 리턴해주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다운로드는 받은 데이터를 가지고 엑셀파일을 만들고 응답으로는 성공메세지를 보냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀파일로 내보내는건 따로 utils 폴더를 만들어서 그 안에 작성을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/exceljs#contents&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;exceljs&lt;/a&gt;라는 라이브러리를 사용해서 간단하게 만들 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1665295855601&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Excel = require('exceljs');

const writeExcelFile = async (data) =&amp;gt; {
    const workbook = new Excel.Workbook();   //워크북생성
    const worksheet = workbook.addWorksheet(&quot;sheet1&quot;);  //시트생성. 괄호안은 시트명

    if (data.length) {   // 조건에 맞는 데이터가 존재할 때만 아래가 실행된다. 없는데 파일을 다운로드하면 빈 엑셀파일 생성
        const columns = Object.keys(data[0]);  // 데이터가 리스트에 객체 여러개가 담겨오기 때문에 맨처음 객체의 키만 가지고 컬럼을 만든다

        worksheet.columns = columns.map((column) =&amp;gt; ({
        header: column, // 컬럼 이름(치매센터명, 치매센터유형,.....)
        key: column, // data에서 컬럼의 값을 구분하기 위한 key
        }));

        // 두 번째 줄부터 데이터 행들을 한꺼번에 입력
        worksheet.insertRows(2, data);
    }
    const filename = `치매센터${new Date().getTime()}.xlsx`;  // 파일명 중복 방지를 위해 현재시간을 파일명에 넣음
    await workbook.xlsx.writeFile(filename);   // 위에서 지정한 파일명으로 파일생성
};

module.exports = { writeExcelFile };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hospital/download로 요청을 보내면 프로젝트 폴더에 파일이 생성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;263&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mfMYX/btrN4EJgWzH/dDxmp06BZAMASuokLrvJt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mfMYX/btrN4EJgWzH/dDxmp06BZAMASuokLrvJt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mfMYX/btrN4EJgWzH/dDxmp06BZAMASuokLrvJt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmfMYX%2FbtrN4EJgWzH%2FdDxmp06BZAMASuokLrvJt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;263&quot; height=&quot;136&quot; data-origin-width=&quot;263&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1201&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G8Y0U/btrOciLeCRo/WZM5qwok3qga2VMkV2E8xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G8Y0U/btrOciLeCRo/WZM5qwok3qga2VMkV2E8xk/img.png&quot; data-alt=&quot;admin 유저가 대표자명 '필'로 검색했을 때 데이터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G8Y0U/btrOciLeCRo/WZM5qwok3qga2VMkV2E8xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG8Y0U%2FbtrOciLeCRo%2FWZM5qwok3qga2VMkV2E8xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1201&quot; height=&quot;312&quot; data-origin-width=&quot;1201&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;admin 유저가 대표자명 '필'로 검색했을 때 데이터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;추가구현-검색기능&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &amp;lsquo;치매센터명', &amp;lsquo;운영기관대표자명', &amp;lsquo;운영기관전화번호': 단어 부분 검색 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; (hospitals.name, hospitals.representative, hospitals.operator_contact)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; where 항목 like &quot;%검색어%&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;&amp;lsquo;치매센터유형':&amp;nbsp;모든&amp;nbsp;단어&amp;nbsp;일치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; (types.name)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; where 항목 = &quot;검색어&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;-&amp;nbsp;&amp;lsquo;의사인원수&amp;rsquo;,&amp;nbsp;&amp;lsquo;간호사인원수',&amp;nbsp;&amp;lsquo;사회복지사인원수':&amp;nbsp;일정&amp;nbsp;숫자&amp;nbsp;이상&amp;nbsp;검색&amp;nbsp;가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; (hospitals.doctor, hospitals.nurse, hospitals.social_worker)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; where 항목 &amp;gt;= 입력숫자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색은 쿼리스트링으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/hospital?name=&quot;어쩌고&quot; 이렇게 받을거다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 온 요청에서 &quot;어쩌고&quot;는 req.query.name에 담겨있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1665252493626&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 컨트롤러
const reqQuery = req.query;

// Dao
const getHospitalData = async (provinceId, reqQuery) =&amp;gt; {  
  const {name, representative, operatorcontact, type, doctor, nurse, socialworker} = reqQuery;
  
  ...
  
  if (name) {
    query += ` AND h.name LIKE &quot;%${name}%&quot;`;
  }
  if (representative) {
    query += ` AND h.representative LIKE &quot;%${representative}%&quot;`;
  }
  if (operatorcontact) {
    query += ` AND h.operator_contact LIKE &quot;%${operatorcontact}%&quot;`;
  }
  if (type) {
    query += ` AND t.name = &quot;${type}&quot;`;
  }
  if (doctor) {
    query += ` AND h.doctor &amp;gt;= ${doctor}`;
  }
  if (nurse) {
    query += ` AND h.nurse &amp;gt;= ${nurse}`;
  }
  if (socialworker) {
    query += ` AND h.social_worker &amp;gt;= ${socialworker}`;
  }

  query += &quot;;&quot;
  
  return await myDataSource.query(query);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 req.query를 reqQuery에 담아서 Dao까지 보내서 하나하나씩 있으면 조건에 추가했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키가 아예 들어오지 않으면 undefined로 falsey하고 키만 넣고 아무것도 넣지 않으면 빈 문자열로 falsey하기 때문에 키값만 가지고 조건에 넣을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 기능은 구현했지만 이게 최선일까.................ㅠ너무...길고요....dao에는 sql만 들어가고 로직처리는 service에서 한다고 들었는데 dao에 조건문이 이렇게 많이 들어가도 되는것인가? 근데 고친다면 어떻게 고쳐야하는거지!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 아직 로그인기능도 적용안했고 리드미도 작성해야하니깐 이건 일단 추가구현을 한것에 만족하고 패스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/exceljs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.npmjs.com/package/exceljs&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tesseractjh.tistory.com/236&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://tesseractjh.tistory.com/236&lt;/a&gt;&lt;/p&gt;</description>
      <category>wecode</category>
      <category>과제</category>
      <category>백엔드</category>
      <category>원티드</category>
      <category>코스</category>
      <category>프리온보딩</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/135</guid>
      <comments>https://ginghambagle.tistory.com/135#entry135comment</comments>
      <pubDate>Sun, 9 Oct 2022 21:46:38 +0900</pubDate>
    </item>
    <item>
      <title>프리온보딩 | 2차과제 - 1: db모델링, 데이터조회기능</title>
      <link>https://ginghambagle.tistory.com/134</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;치매센터 관리자, 지역별 담당자용 어플리케이션 만들기!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;db모델링&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ok33t/btrN66xrCof/ZV2tOgUB3rUtCjWUrO4Jb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ok33t/btrN66xrCof/ZV2tOgUB3rUtCjWUrO4Jb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ok33t/btrN66xrCof/ZV2tOgUB3rUtCjWUrO4Jb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fok33t%2FbtrN66xrCof%2FZV2tOgUB3rUtCjWUrO4Jb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;785&quot; height=&quot;708&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 모델링은 이런식으로 했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;province_id가 null이면 대표관리자인걸 알수 있지만 is_admin 컬럼을 하나 더 추가했다. -&amp;gt; province_id가 없는걸로만 admin을 판단하면 담당자가 아직 지역 배정이 안됐을경우 admin권한을 가져버리는걸 막기위해!&lt;/li&gt;
&lt;li&gt;hospitals에는 &lt;a href=&quot;https://www.data.go.kr/data/15021138/standard.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;전국치매센터표준데이터&lt;/a&gt; 이 데이터들이 들어가는데 주소데이터를 파싱해서 시/도(특별시 광역시나 도)별로 분류할 수 있도록 province_id를 넣어서 지역 테이블과 연결시켰다.&lt;/li&gt;
&lt;li&gt;그리고 types에는 센터의 종류(데이터에서 '치매센터유형'에 해당하는것)를 넣었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;내 기능&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 조회해서 엑셀파일로 다운받을 수 있는 기능을 만들어야함&lt;/li&gt;
&lt;li&gt;지역관리자는 소속지역의 데이터만 조회할 수 있고, 대표관리자는 모든 데이터 조회 가능이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  데이터조회&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 토큰에 넘어오는 id값으로 admin인지, 어디지역 관리자인지 알아내는 코드와 sql문을 작성하려고 했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰에 is_admin과 province_id를 넣으면 id만 받아서 관리자인지, 어느지역 담당자인지 확인할 필요도 없고 토큰발급때만 user테이블에 조회가 들어가니까 데이터베이스 접근 횟수도 줄일 수 있어서 토큰에 id, is_admin, province_id를 담기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀 컬럼명이 원래 데이터 필드명이랑 같아야 한다는 조건이 있어서 영어로 넣어놓은 컬럼명을 다시 한국말로 볼수있게 바꿨다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 admin은 모든 데이터 조회가 가능하고 나머지는 본인 지역만 조회가 가능해서 admin일때, 아닐때를 나눠서 where절만 추가하는것으로 바꿨다.&lt;/p&gt;
&lt;pre id=&quot;code_1665219541051&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// models/hospitalDao.js
const getHospitalData = async (provinceId) =&amp;gt; {  
  let query = `SELECT
    h.name AS 치매센터명,
    t.name AS 치매센터유형,
    h.street_address AS 소재지도로명주소,
    h.address AS 소재지지번주소,
    h.latitude AS 위도,
    h.longitude AS 경도,
    h.establishment AS 설립연월,
    h.area AS 건축물면적,
    h.facility AS 부대시설정보,
    h.doctor AS 의사인원수,
    h.nurse AS 간호사인원수,
    h.social_worker AS 사회복지사인원수,
    h.extra_people AS 기타인원현황,
    h.operator AS 운영기관명,
    h.representative AS 운영기관대표자명,
    h.operator_contact AS 운영기관전화번호,
    h.trust AS 운영위탁일자,
    h.data AS 주요치매관리프로그램소개,
    h.management_contact AS 관리기관전화번호,
    h.management AS 관리기관명,
    h.standard_date AS 데이터기준일자,
    p.name AS 제공기관명
  FROM hospitals AS h
  JOIN types AS t ON t.id=h.type_id
  JOIN provinces AS p ON p.id=h.province_id`;

  if (provinceId) {
    query += ` WHERE province_id = ${provinceId}`;
  }
  query += &quot;;&quot;
  
  return await myDataSource.query(query);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예외처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;is_admin=0이고 province_id=null일경우는 빈 배열로 결과가 나와서 따로 예외처리를 할까말까 하다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트입장에서 아무것도 없는데 200이 뜨면 뭐가 잘못됐는지 모르기때문에 예외처리를 해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 admin인데 관리지역이 있을때도 예외처리를 해줬다.&lt;/p&gt;
&lt;pre id=&quot;code_1665221233868&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// services/hospitalService.js
const getHospitalDataService = async (isAdmin, provinceId) =&amp;gt; {
  if (isAdmin &amp;amp;&amp;amp; provinceId) {
    throw new ErrorCreator(&quot;admin cannot have province_id&quot;, 400);
  }
  if (!isAdmin &amp;amp;&amp;amp; !provinceId) {
    throw new ErrorCreator(&quot;province_id not provided&quot;, 400);
  }
  return await hospitalDao.getHospitalData(provinceId);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>wecode</category>
      <category>백엔드</category>
      <category>원티드</category>
      <category>코드</category>
      <category>프리온보딩</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/134</guid>
      <comments>https://ginghambagle.tistory.com/134#entry134comment</comments>
      <pubDate>Sun, 9 Oct 2022 00:28:21 +0900</pubDate>
    </item>
    <item>
      <title>프리온보딩 | 1차과제 - 3</title>
      <link>https://ginghambagle.tistory.com/132</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;회의&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유닛테스트는 각자 맡은 기능별로 할수있는 사람만 하기로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api명세서는 포스트맨 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;기능구현&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정유저 정보수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 비활성유저 정보 수정하려는경우, 없는유저 정보 수정하려는 경우로 예외처리를 나눠야겠다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 처음부터 라우터, 레이어드 패턴 적용해서 짜봤다&lt;/p&gt;
&lt;pre id=&quot;code_1665046569412&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// routers/user_router.js

const errorHandler = require(&quot;../middlewares/error_handler&quot;);
const userController = require(&quot;../controllers/user_controller&quot;);

router.patch(&quot;/:userId&quot;, errorHandler(userController.editUserProfile));



// controllers/user_controller.js

const userService = require(&quot;../services/user_service&quot;);

const editUserProfile = async (req, res) =&amp;gt; {
    const { userId } = req.params;
    const { name, birthday, height, mobileNumber } = req.body;
    await userService.editUserProfile(userId, name, birthday, height, mobileNumber);
    res.status(200).json({ message: &quot;USER_EDITED&quot; })
};

module.exports = {
	...
    editUserProfile
};



// services/user_services.js

const userDao = require(&quot;../models/user_dao&quot;)

const editUserProfile = async (userId, name, birthday, height, mobileNumber) =&amp;gt; {
    return await userDao.editUserProfile(userId, name, birthday, height, mobileNumber);
};

module.exports = {
    ...
    editUserProfile
};



// models/user_dao.js

const editUserProfile = async (userId, name, birthday, height, mobileNumber) =&amp;gt; {
  return await pool.query(
    `
    UPDATE users 
    SET 
      name = ?,
      birthday = ?,
      height = ?,
      mobile_number = ?
    WHERE id = ?
    ;`, [name, birthday, height, mobileNumber, userId]
  );
};

module.exports = {
  ...
  editUserProfile
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 회원수정페이지에 들어가면 원래 정보가 있고, 수정버튼을 누르면 수정된 정보 안된정보 그대로 요청과 함께 보내는걸로 가정하고 모든 컬럼을 요청에 담겨온 값으로 변경하는 코드로 작성했다&lt;s&gt;(시간이없어)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유효성검사와 키에러 처리는 회원가입 구현할때 사용한 코드를 재활용 했다.&amp;nbsp; -&amp;gt; 다른팀원 코드라서 에러처리부분이 다르게 돼있어서 에러코드가 전달이 안돼서 500에러로 처리됐다. -&amp;gt; 에러핸들러의 코드저장 키 변경(status -&amp;gt; statusCode)&lt;/p&gt;
&lt;pre id=&quot;code_1665047587370&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const errorHandler = () =&amp;gt; {
  const err = new Error(&quot;INVALID_DATA_INPUT&quot;);
  err.statusCode = 500;   // 다른분의 errorHandler. statusCode에 에러코드 저장
  throw err;
};

//=====================================================================================

// 이건 내 코드에 적용되는 errorHandler
// 원래 status로 돼있는데 위에서 err.statusCode로 돼있어서 err.status에는 아무것도 안들어간다. -&amp;gt; statusCode로 변경
  
module.exports = class ErrorCreator extends Error {
    constructor(message, statusCode) {
        super(message);
        this.name = this.constructor.name;

        Error.captureStackTrace(this, this.constructor);

        this.statusCode = statusCode || 500;
    }
};

function errorHandler(asyncController) {
    return async (req, res) =&amp;gt; {
        try {
            await asyncController(req, res)
        } catch (err) {
            res.status(err.statusCode ? err.statusCode : 500).json({ message : err.message });
        } 
    }
}

module.exports = errorHandler;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유효성검사에 키-숫자값 체크하는게 없어서 문자를 넣으면 500에러가 났다. -&amp;gt; 키 유효성검사 추가&lt;/p&gt;
&lt;pre id=&quot;code_1665048802695&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// services/user_service.js

const checkVaildate = async (name, birthday, height, mobile_number) =&amp;gt; {
    ...

    const validateHeight = /[0-9]/;
        if(!validateHeight.test(height)){
            const err = new Error('INVALID_HEIGHT')
            err.statusCode = 400
            throw err
    }
	...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;존재하지 않는 유저정보 변경하려할때도 다른코드 재활용하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+ 비활성화된 유저정보 수정하려하면 에러처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;존재하는 유저인지 체크 -&amp;gt; 활성화상태인 유저인지 체크 -&amp;gt; 키에러 체크 -&amp;gt; 유효성검사 -&amp;gt;수정&lt;/p&gt;
&lt;pre id=&quot;code_1665048831532&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const editUserProfile = async (userId, name, birthday, height, mobileNumber) =&amp;gt; {
    const isExist = await userDao.isExistUser(userId);
    if(!isExist.length){
        throw new ErrorCreator(&quot;USER_NOT_EXISTS&quot;, 404);
    }
    const isActive = await userDao.checkActiveUser(userId);
    if (!isActive) {
        throw new ErrorCreator(&quot;INVALID_USER&quot;, 404);
    }

    if (!name || !birthday || !height || !mobileNumber ) {
        throw new ErrorCreator(&quot;KEY_ERROR&quot;, 400);
    }

    await checkVaildate(name, birthday, height, mobileNumber);

    return await userDao.editUserProfile(userId, name, birthday, height, mobileNumber);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 폰번호 유효성검사가 /^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})$/ 이렇게돼있는데 중간에 작대기가 없어도 유효성검사에 안걸린다! 일단패쓰...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 내가 작성한거 말고는 예외처리 상태코드가 거의 409 conflict로 돼있는데 처음보는코드다 뭔지 찾아봐야지 -&amp;gt; HTTP 409 Conflict응답 상태 코드는 요청이 대상 리소스의 현재 상태와 충돌함을 나타냅니다. -&amp;gt; 옛날버전의 파일을 업데이트하려고 할때 발생한다고 예시로 있는데 엄...&lt;/p&gt;</description>
      <category>wecode</category>
      <category>백엔드</category>
      <category>원티드</category>
      <category>프리온보딩</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/132</guid>
      <comments>https://ginghambagle.tistory.com/132#entry132comment</comments>
      <pubDate>Thu, 6 Oct 2022 23:48:24 +0900</pubDate>
    </item>
    <item>
      <title>프리온보딩 | 1차과제 - 2</title>
      <link>https://ginghambagle.tistory.com/131</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;회의&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;깃허브&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pr템플릿 추가 -&amp;gt; 팀으로 프로젝트 하는 부분에 있어서 그래도 서로 리뷰를 하고 머지를 해야될것같아서 추가했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;db&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키(height) 데이터타입 float으로 수정 -&amp;gt; decimal, double, float중에서 정확하지 않아도 상관없는 데이터니까 빠르고 적은 메모리를 차지하는 타입으로 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;record_data에 타임스탬프 안찍기로 결정 -&amp;gt; 계속 고민했는데 각 기록은 어차피 한나의 기록에 종속된거라서 타임스탬프 추가 안하기로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;schema.sql .gitignore에 추가 -&amp;gt; schema.sql에 어디까지 마이그레이션 진행했는지 기록돼있어서 다른사람이 같은 마이그레이션 파일을 가지고 마이그레이트 하면 제대로 작동안하니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeorm 안쓰는걸로 변경 -&amp;gt; 조건에 orm사용하지 말라는게 있었는데 typeorm을 원래도 db랑 연결 목적으로만 사용하고 쿼리를 직접 쓰고있어서 그냥 사용하는걸로 했다가, 사용하지 않는걸로 변경&lt;/p&gt;
&lt;pre id=&quot;code_1664958562132&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// models/common.js
const mysql = require(&quot;mysql2/promise&quot;);

const pool = mysql.createPool({
  host: process.env.MYSQL_HOST,
  port: process.env.MYSQL_PORT,
  user: process.env.MYSQL_USERNAME,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DATABASE,
  connectionLimit: 10,
});

module.exports = pool;

// server.js
const pool = require(&quot;./models/common&quot;);
...

app.get(&quot;/test&quot;, async (req, res) =&amp;gt; {
    const [result] = await pool.query(`select * from users;`);
    res.json({message: result});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;기능&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 측정기록+데이터 가져오기&lt;u&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;측정기록을 아이디로 조회하면 데이터도 가져오는데 유저삭제를 하면 비활성화되고 데이터는 살아있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 살아있는 데이터를 조회하려고 했을때 그냥 조회가 되게 할것인지, 삭제한 유저의 정보니까 보여주지 않을것인지 회의를 했고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비활성화된 유저의 기록을 조회하려고 하면 보여주지 않는것으로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;기능구현&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;특정 측정기록+데이터 가져오기&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ySEmc/btrNSNZ4ugJ/KzBmxDiWVsGq8s7F3HVsk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ySEmc/btrNSNZ4ugJ/KzBmxDiWVsGq8s7F3HVsk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ySEmc/btrNSNZ4ugJ/KzBmxDiWVsGq8s7F3HVsk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FySEmc%2FbtrNSNZ4ugJ%2FKzBmxDiWVsGq8s7F3HVsk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;940&quot; height=&quot;290&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;records의 id를 가지고 기록을 조회했을때 네 테이블을 전부 조인해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저정보, 기록일시, 당시몸무게, 각 타입별 타입명과 데이터를 모두 보여줘야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 기록에 타입별로 여러 데이터가 들어있을 수 있어서 응답 데이터 형태는&lt;/p&gt;
&lt;pre id=&quot;code_1664964129757&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    유저정보: ...,
    기록일시: ...,
    기록데이터: [
        {
            측정타입:어쩌고,
            수치: 몇몇,
            ...
        },
        {
            ...
        },
        ...
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 나오게 하고싶었다. -&amp;gt; JSON_ARRAYAGG(JSON_OBJECT())사용&lt;/p&gt;
&lt;pre id=&quot;code_1664964264517&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [[result]] = await pool.query(`
        SELECT
            users.id as userId,
            users.name as userName,
            users.birthday as userBirthday,
            users.height as userHeight,
            users.mobile_number as userMobileNumber,
            records.id as recordId,
            records.weight as userWeightOnRecord,
            records.created_at as recordDateTime,
            JSON_ARRAYAGG(
                JSON_OBJECT(
                    'recordDataId', record_data.id,
                    'recordTypeId', record_data.record_type_id,
                    'recordType', record_types.type,
                    'recordDataOnType', record_data.data
                )
            ) as recordData
        FROM record_data
        JOIN record_types ON record_types.id = record_data.record_type_id
        JOIN records ON records.id = record_data.record_id
        JOIN users ON users.id = records.user_id
        WHERE records.id = ?
        GROUP BY records.id
    ;`, [recordId]);
    res.status(200).json({result: result});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 원하는 결과가 배열로 두번 감싸져서 나와서 두번 벗겼다[[result]]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;예외처리&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 삭제(비활성화된) 유저의 기록이면 데이터를 보내주지 않는다. -&amp;gt; 해당 기록의 주인의 is_active값 확인&lt;/p&gt;
&lt;pre id=&quot;code_1664965622068&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [[isActive]] = await pool.query(`
        SELECT users.is_active 
        FROM users
        JOIN records ON users.id = records.user_id
        WHERE records.id=?;`, [recordId]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 isActive에는 {is_active: 1 또는 0}이 들어있다.&lt;/p&gt;
&lt;pre id=&quot;code_1664965706404&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    if(!isActive.is_active){
        return res.status(400).json({message: &quot;INVALID_RECORD&quot;})
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 isActive.is_active로 조건을 줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 없는데이터 요청했을경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기록의 id값으로 요청이 오는데 기록 자체가 없을 경우&lt;/p&gt;
&lt;pre id=&quot;code_1664967908041&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    const [[isExists]] = await pool.query(`
    SELECT EXISTS (SELECT 1 FROM records WHERE id = &quot;${recordId}&quot;);`);

    if (!Object.values(isExists)[0]) {
        return res.status(404).json({message: &quot;RECORD_DOES_NOT_EXIST&quot;})
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isExists의 값은 { 'EXISTS (SELECT id FROM records WHERE id = &quot;4&quot;)': 1 } 이렇게 들어가있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 1을 뽑으려고 Object.values(isExists)[0] 를 사용했다ㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;다른사람 코드를 보니까 이렇게까지 안했던데 어떻게한거지.......&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자원이 존재하지 않는다는 의미인 404를 에러코드로 넣었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 레이어드 나눠진채로 짜는게 익숙하지 않아서 일단 이렇게 server.js에 전부 하나로 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;레이어드패턴&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 나누기&lt;/p&gt;
&lt;pre id=&quot;code_1664975809222&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// server.js
const recordController = require(&quot;./controllers/record_controller&quot;)

app.get(&quot;/records/:recordId&quot;, recordController.getRecordWithData);



// controllers/record_controller.js
const recordService = require(&quot;../services/record_service&quot;)

const getRecordWithData = async (req, res) =&amp;gt; {
    const {recordId} = req.params;
    const result = await recordService.getRecordWithData(recordId);
    res.status(200).json({result: result});
};

module.exports = {getRecordWithData}



// services/record_services.js
const recordDao = require(&quot;../models/record_dao&quot;)

const getRecordWithData = async (recordId) =&amp;gt; {
    console.log(&quot;service1&quot;);
    return await recordDao.getRecordWithData(recordId);
};

module.exports = {getRecordWithData}



// models/record_dao.js
const pool = require(&quot;./common&quot;);

const getRecordWithData = async(recordId) =&amp;gt; {
    console.log(&quot;model1&quot;);
    const [[result]] = await pool.query(`
        SELECT
            users.id as userId,
            users.name as userName,
            users.birthday as userBirthday,
            users.height as userHeight,
            users.mobile_number as userMobileNumber,
            records.id as recordId,
            records.weight as userWeightOnRecord,
            records.created_at as recordDateTime,
            JSON_ARRAYAGG(
                JSON_OBJECT(
                    'recordDataId', record_data.id,
                    'recordTypeId', record_data.record_type_id,
                    'recordType', record_types.type,
                    'recordDataOnType', record_data.data
                )
            ) as recordData
        FROM record_data
        JOIN record_types ON record_types.id = record_data.record_type_id
        JOIN records ON records.id = record_data.record_id
        JOIN users ON users.id = records.user_id
        WHERE records.id = ?
        GROUP BY records.id
    ;`, [recordId]);
    console.log(&quot;model2&quot;);
    return result
};

module.exports = {getRecordWithData}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상요청일때만 옮겨놨다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 에러처리하고 라우터 적용하면 된다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;라우터&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664978481017&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// server.js
// 위에 코드블럭에 있던 두줄 없어짐


// routes/index.js
const express = require(&quot;express&quot;);
const router = express.Router();

const recordRouter = require(&quot;./record_router&quot;);

router.use(&quot;/records&quot;, recordRouter)

module.exports = router;


// routes/record_router.js
const express = require(&quot;express&quot;);
const recordController = require(&quot;../controllers/record_controller&quot;)

const recordRouter = express.Router();

recordRouter.get(&quot;/:recordId&quot;, recordController.getRecordWithData)


module.exports = recordRouter;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;다시 에러처리(예외처리)&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;181&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctjL2z/btrNRDc09Vx/g3y3CkqHH1aPRvQypPNMSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctjL2z/btrNRDc09Vx/g3y3CkqHH1aPRvQypPNMSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctjL2z/btrNRDc09Vx/g3y3CkqHH1aPRvQypPNMSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctjL2z%2FbtrNRDc09Vx%2Fg3y3CkqHH1aPRvQypPNMSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;181&quot; height=&quot;64&quot; data-origin-width=&quot;181&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 열심히 던져보다가 트라이캐치...매번써야돼..?싶어서 위코드 레포 구경하다가 편리한 도구를 복붙해왔다 복붙도 실력이야~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;error_creator.js는 메세지랑 상태코드 던져주면 에러 만들어주는거,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;error_handler.js는 에러 잡으면 상태코드랑 메세지 리턴해주는거&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664991957369&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// routes/record_router.js
const errorHandler = require(&quot;../middlewares/error_handler&quot;);
const recordRouter = express.Router();

recordRouter.get(&quot;/:recordId&quot;, errorHandler(recordController.getRecordWithData));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이렇게 라우터에 던질때부터 errorHandler에 감싸서 던지면 안에서 에러를 throw만 해도 메세지랑 코드가 리턴된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외처리한거 어디다가 끼워넣어야할지 기웃대면서 생각하다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 목적대로 sql은 dao에, sql결과가지고 에러내는건 로직처리하는 service에 넣는게 맞는거같아서 각 예외처리의 sql과 if문을 갈랐다&lt;/p&gt;
&lt;pre id=&quot;code_1664992218214&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// models/record_dao.js

// 없는기록 불렀을때
const checkExistRecord = async (recordId) =&amp;gt; {
    const [[isExists]] = await pool.query(`
    SELECT EXISTS (SELECT 1 FROM records WHERE id = &quot;${recordId}&quot;);`);
    return Object.values(isExists)[0]
}

// 비활성화유저의 기록 불렀을때
const checkActiveRecord = async (recordId) =&amp;gt; {
    const [[isActive]] = await pool.query(`
        SELECT users.is_active 
        FROM users
        JOIN records ON users.id = records.user_id
        WHERE records.id=?;`, [recordId]);
    return isActive.is_active
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;record_dao.js에 이렇게 예외처리에 필요한 sql문 추가하고 조건으로 판단할 데이터 리턴해주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664992303072&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// services/record_service.js

const getRecordWithData = async (recordId) =&amp;gt; {
    // 존재안할때
    const isExists = await recordDao.checkExistRecord(recordId);
    if (!isExists) {
        throw new ErrorCreator(&quot;RECORD_NOT_EXISTS&quot;, 404)
    }

    // 비활성화유저꺼일때
    const isActive = await recordDao.checkActiveRecord(recordId);
    if (!isActive) {
        throw new ErrorCreator(&quot;INVALID_RECORD&quot;, 404)
    }

    return await recordDao.getRecordWithData(recordId);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 추가해서 완성...자야지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>wecode</category>
      <category>과제</category>
      <category>백엔드코스</category>
      <category>원티드</category>
      <category>프리온보딩</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/131</guid>
      <comments>https://ginghambagle.tistory.com/131#entry131comment</comments>
      <pubDate>Thu, 6 Oct 2022 03:00:17 +0900</pubDate>
    </item>
    <item>
      <title>프리온보딩 | 1차과제 - 1</title>
      <link>https://ginghambagle.tistory.com/130</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회원, 회원 건강기록 관리 앱 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;데이터모델링&lt;/u&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Eocir/btrNOfPpq7j/g6io3i8pJDB1Yswvsogmd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Eocir/btrNOfPpq7j/g6io3i8pJDB1Yswvsogmd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Eocir/btrNOfPpq7j/g6io3i8pJDB1Yswvsogmd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEocir%2FbtrNOfPpq7j%2Fg6io3i8pJDB1Yswvsogmd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;935&quot; height=&quot;292&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유저 삭제는 진짜 데이터를 지우지 않고 비활성화 상태로 두는거라서 is_active컬럼을 추가해서 삭제시 비활성화상태로 바뀌도록 했다.&lt;/li&gt;
&lt;li&gt;회원 측정 데이터는 같이 삭제되면 안되는데, 유저 삭제가 진짜 삭제가 아니기 때문에 외래키제약은 그냥 on delete cascade로 줬다. 당장은 그냥 비활성화 상태지만 나중에 보관기간이 지나고 회원정보를 진짜로 삭제한다면 기록도 같이 삭제되어야 할것같기 때문..&lt;/li&gt;
&lt;li&gt;mysql은 boolean타입이 없다고 한다. 우리가 boolean으로 지정해서 true false란 값을 넣을순 있는데 내부적으로 tinyint로 바꿔서 true면 1 false면 0을 저장한다고함. 어쩐지 프로젝트때 boolean타입넣어서 true false로 저장한게 1, 0으로 들어가더라~암튼 그래서 협업할때는 아예 tinyint로 지정하는것이 좋다. boolean이라고 해놓고 0, 1로 들어가있으면 헷갈릴수 잇으니까!&lt;/li&gt;
&lt;li&gt;records에 항목별 record_data가 따라오는거라서 각 측정항목에 대한 측정시간기록은 하지 않고 전체 측정시간만 기록하도록 했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;내가 맡은 기능이 데이터 수정/조회라서 테스트 데이터 넣다보니 height데이터타입을 int로 한걸 발견했다. 몸무게처럼 실수형으로 바꿔야함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;레이어드패턴&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기세팅부터 controllers/services/models 나뉘어있어서 레이어드패턴을 먼저 공부했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;721&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eE5G72/btrNIKpTd8W/nlkMVI9aEZzKZF6uMGXkkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eE5G72/btrNIKpTd8W/nlkMVI9aEZzKZF6uMGXkkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eE5G72/btrNIKpTd8W/nlkMVI9aEZzKZF6uMGXkkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeE5G72%2FbtrNIKpTd8W%2FnlkMVI9aEZzKZF6uMGXkkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;721&quot; height=&quot;202&quot; data-origin-width=&quot;721&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이어드패턴: 파일을 구조화해서 파일마다 역할을 명확하게 해서 각 레이어의 코드가 서로 독립적이고 서로에게 미치는 영향 최소화해서 가독성 높이고 재사용성을 높이는게 목적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;path parameter&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 맡은 기능은 특정회원 정보수정, 특정 측정기록+측정데이터 불러오기 두가지인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 유저중 특정유저, 측정기록중 특정 기록에 대한 요청이라서 둘다 path parameter를 이용해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;users/유저아이디, records/측정기록 아이디 url로 요청을 받는걸로하면 될거같은데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스프레스에서 path parameter 받는법은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'/:id' 이렇게 하고 id값은 req.params.id로 빼내면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1664903585462&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// server.js
app.get(&quot;/records/:recordId&quot;, (req, res) =&amp;gt; {
    console.log(req.params.recordId);
    res.json({message:&quot;테스트&quot;});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uR64R/btrNPjjw3v5/BBQykV0wLwYT2dtRdUNAm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uR64R/btrNPjjw3v5/BBQykV0wLwYT2dtRdUNAm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uR64R/btrNPjjw3v5/BBQykV0wLwYT2dtRdUNAm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuR64R%2FbtrNPjjw3v5%2FBBQykV0wLwYT2dtRdUNAm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;695&quot; height=&quot;88&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;mysql에러해결&lt;/u&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1664907675997&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  어쩌고저쩌고
  code: 'ER_NOT_SUPPORTED_AUTH_MODE',
  errno: 1251,
  sqlMessage: 'Client does not support authentication protocol requested by server; consider upgrading MySQL client',
  sqlState: '08004',
  fatal: true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 에러가 나서 검색해봤는데 클라이언트에서 mysql 패스워드 플러그인 &quot;caching_sha2_password&quot;을 못알아먹으니까&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #e3e6e8; color: #232629;&quot;&gt;ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 플러그인을 &quot;mysql_native_password&quot;로 바꾸라는 내용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 그전에는 잘 됐는데 왜바꿔야돼?해서 더 검색해봤는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mysql2가 이럴때 쓰는거라고 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 더 검색하는데 mysql대신 강제로 mysql2로 mysql클라이언트 설정하는법 이런게 나왔다 -&amp;gt; 이거 해결할려면 mysql이 아니라 mysql2를 써야한다는거? -&amp;gt; package.json을 확인하니까 mysql, mysql2가 둘다 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 mysql을 삭제하니까 바로 해결됐다.(이제보니까 에러메세지도 클라이언트를 업그레이드 하라고 나와있다. mysql-&amp;gt;mysql2로 바꾸라는거였나보다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;447&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chaj62/btrNNnUKVHI/OxksOUeByB3EHmVdm8poJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chaj62/btrNNnUKVHI/OxksOUeByB3EHmVdm8poJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chaj62/btrNNnUKVHI/OxksOUeByB3EHmVdm8poJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchaj62%2FbtrNNnUKVHI%2FOxksOUeByB3EHmVdm8poJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;516&quot; height=&quot;447&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;447&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자야지....&lt;/p&gt;</description>
      <category>wecode</category>
      <category>백엔드</category>
      <category>원티드</category>
      <category>프리온보딩</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/130</guid>
      <comments>https://ginghambagle.tistory.com/130#entry130comment</comments>
      <pubDate>Wed, 5 Oct 2022 02:17:01 +0900</pubDate>
    </item>
    <item>
      <title>node.js | 인스타그램: 비밀번호 암호화(bcrypt)</title>
      <link>https://ginghambagle.tistory.com/129</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 비밀번호를 암호화해서 저장하기 위해 bcrypt라이브러리를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비밀번호를 유추할 수 없게 하기 위해 솔팅, 키스트레칭을 해서 해시를 하는데 bcrypt를 사용하면 해시된 비밀번호에 솔트값도 같이 저장이 되기 때문에 비밀번호를 비교하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;설치&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664813253388&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install bcrypt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;사용&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664813485308&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const bcrypt = require('bcrypt');
const saltRounds = 10;
const myPlaintextPassword = 's0/\/\P4$$w0rD'; // 얘를 암호화할거
const someOtherPlaintextPassword = 'not_bacon';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;비밀번호 암호화하기&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664813448497&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 솔트값을 만들고 해당 솔트값으로 해싱
bcrypt.genSalt(saltRounds, function(err, salt) {
    bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
        // Store hash in your password DB.
    });
});

// 2. 위 작업을 한번에 하는거(둘다 같은 결과가 나온다)
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
    // Store hash in your password DB.
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;(db에 저장된)암호화된 비밀번호와 입력 비밀번호 비교&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664813530398&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Load hash from your password DB.
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
    // result == true
});
bcrypt.compare(someOtherPlaintextPassword, hash, function(err, result) {
    // result == false
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;회원가입에 적용&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664814013222&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.post('/users', async (req, res) =&amp;gt; {
    const {email, nickname, password, profileImage} = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);
    await myDataSource.query(
        `INSERT INTO users (email, nickname, password, profile_image)
        VALUES (?, ?, ?, ?)`
        , [email, nickname, hashedPassword, profileImage]);
    
    res.status(201).json({&quot;message&quot; : &quot;userCreated&quot;});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wSBFF/btrNIKoO7Y6/KRtACAxNa5dCzzTikFcKjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wSBFF/btrNIKoO7Y6/KRtACAxNa5dCzzTikFcKjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wSBFF/btrNIKoO7Y6/KRtACAxNa5dCzzTikFcKjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwSBFF%2FbtrNIKoO7Y6%2FKRtACAxNa5dCzzTikFcKjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;492&quot; height=&quot;373&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1316&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QsA1E/btrNAL3qExU/RKxPYUsGCsiVkVKv1tgX9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QsA1E/btrNAL3qExU/RKxPYUsGCsiVkVKv1tgX9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QsA1E/btrNAL3qExU/RKxPYUsGCsiVkVKv1tgX9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQsA1E%2FbtrNAL3qExU%2FRKxPYUsGCsiVkVKv1tgX9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1316&quot; height=&quot;205&quot; data-origin-width=&quot;1316&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;확인&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664814536060&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bcrypt.compare(&quot;encrypted&quot;, &quot;$2b$10$AumIqWJxz6Lu194MKWmLeeeBPqUT61ggANG6uobtT8tvS/Jomd4be&quot;, (err, result)=&amp;gt;{console.log(result);});
// true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 비밀번호랑 비교해보면 같다고 잘 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/bcrypt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.npmjs.com/package/bcrypt&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/129</guid>
      <comments>https://ginghambagle.tistory.com/129#entry129comment</comments>
      <pubDate>Tue, 4 Oct 2022 01:30:46 +0900</pubDate>
    </item>
    <item>
      <title>node.js | 인스타그램: 게시글 CRUD</title>
      <link>https://ginghambagle.tistory.com/128</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;Create&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요. -&amp;gt; '/postings': 포스팅 관련임을 알아볼수 있다&lt;br /&gt;2. 알맞은 http 메소드를 선정하여서 게시글 내용 및 유저의 id 값을 백엔드 서버에 전달해주세요. -&amp;gt; post: body에 데이터를 담아 보낼때, 뭔가 생성할때&lt;br /&gt;3. 데이터가 생성됬을 때에 알맞는 http 상태코드를 반환해주세요. -&amp;gt; 201: 무언가가 잘 생성됐을때 상태코드&lt;br /&gt;5. http response로 반환하는 JSON 데이터의 형태는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664794839300&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;message&quot; : &quot;postCreated&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2zskk/btrNzEWYIoO/74OcPrk6iLZEuY1kMnb8s1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2zskk/btrNzEWYIoO/74OcPrk6iLZEuY1kMnb8s1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2zskk/btrNzEWYIoO/74OcPrk6iLZEuY1kMnb8s1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2zskk%2FbtrNzEWYIoO%2F74OcPrk6iLZEuY1kMnb8s1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;677&quot; height=&quot;156&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;156&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;req.body에는 어느 유저가 쓰는 글인지를 알기 위해 user의 id가 필수로 들어가고 내용은 없어도됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저-포스팅은 1대다 관계이기 때문에 user_id만 넣으면 관계설정이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664795571203&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app.js
app.post('/postings', async (req, res) =&amp;gt; {
    const {userId, contents} = req.body;
    await myDataSource.query(
        `INSERT INTO postings (user_id, contents)
        VALUES (?, ?)`
        , [userId, contents]);
    res.status(201).json({&quot;message&quot; : &quot;postCreated&quot;});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m1oaU/btrNzFhi8sq/GCXk5m6ljnQMj5aaEpv5bK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m1oaU/btrNzFhi8sq/GCXk5m6ljnQMj5aaEpv5bK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m1oaU/btrNzFhi8sq/GCXk5m6ljnQMj5aaEpv5bK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm1oaU%2FbtrNzFhi8sq%2FGCXk5m6ljnQMj5aaEpv5bK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;727&quot; height=&quot;368&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1027&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgnhwl/btrNB6laVDl/q381klY1gJJtsOykIgBp6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgnhwl/btrNB6laVDl/q381klY1gJJtsOykIgBp6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgnhwl/btrNB6laVDl/q381klY1gJJtsOykIgBp6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgnhwl%2FbtrNB6laVDl%2Fq381klY1gJJtsOykIgBp6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1027&quot; height=&quot;395&quot; data-origin-width=&quot;1027&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 로그인기능 없이 유저아이디를 body에 받기 때문에 회원가입과 똑같이 작성해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;Read&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;게시글&amp;nbsp;리스트&amp;nbsp;불러오기&amp;nbsp;API&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1. 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요. -&amp;gt; '/postings' : posting관련이기때문에&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2. 데이터가 호출될 때의 알맞는 http 상태코드를 반환해주세요. -&amp;gt; 200: 요청에대한 처리가 성공했을 때 코드. 데이터를 읽기만 하니까&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3. http response로 반환하는 데이터의 형태는 다음과 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664795786590&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;data&quot; : [
	{
            &quot;userId&quot;           : 1,
            &quot;userProfileImage&quot; : &quot;userProfileImage1&quot;,
            &quot;postingId&quot;        : 1,
            &quot;postingContent&quot;   : &quot;sampleContent1&quot;
	},
	{
            &quot;userId&quot;           : 2,
            &quot;userProfileImage&quot; : &quot;userProfileImage2&quot;,
            &quot;postingId&quot;        : 2,
            &quot;postingContent&quot;   : &quot;sampleContent2&quot;
	},
	...
]}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;postings 테이블에서 가지고 있지 않은 usreProfileImage가 필요하다. 이 속성은 users테이블에 있는데 userId를 이용해서 가져와야 한다. -&amp;gt; join이용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 각 컬럼의 이름도 카멜케이스로 변경해야한다. -&amp;gt; as 이용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;data&quot; : [{},{},{},...] 의 형태로 반환해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1664797884801&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.get('/postings', async (req, res) =&amp;gt; {
    await myDataSource.query(`
        SELECT 
            users.id AS userId, 
            users.profile_image AS userProfileImage,
            postings.id AS postingId, 
            postings.contents AS postingContent 
        FROM postings JOIN users ON postings.user_id=users.id;
        `, (err, rows) =&amp;gt; {
            res.status(200).json({data: rows});
        });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU8cQD/btrNAyI2vux/3PlBk7dKFO0OuKYT5SHk8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU8cQD/btrNAyI2vux/3PlBk7dKFO0OuKYT5SHk8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU8cQD/btrNAyI2vux/3PlBk7dKFO0OuKYT5SHk8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU8cQD%2FbtrNAyI2vux%2F3PlBk7dKFO0OuKYT5SHk8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;702&quot; height=&quot;580&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;Read2&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;특정&amp;nbsp;유저가&amp;nbsp;작성한&amp;nbsp;게시글&amp;nbsp;상세&amp;nbsp;API&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1. 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요. -&amp;gt; 포스팅을 보는거니까 일단 /postings로 들어가야 할것 같고, user의 id를 쿼리파라미터로 받으면 될 것 같다. -&amp;gt; 아직 모르니까 /postings/user/1로 고정으로 1번유저 포스팅들만 가져오는걸로 하기&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;하나의&amp;nbsp;유저가&amp;nbsp;올린&amp;nbsp;여러개의&amp;nbsp;게시글을&amp;nbsp;보여주는&amp;nbsp;상세&amp;nbsp;페이지용&amp;nbsp;API를&amp;nbsp;작성해주세요.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3. 데이터가 호출될 때에 알맞는 http 상태코드를 반환해주세요. -&amp;gt; 200&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4.&amp;nbsp;Http&amp;nbsp;response로&amp;nbsp;반환하는&amp;nbsp;데이터의&amp;nbsp;형태는&amp;nbsp;다음과&amp;nbsp;같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664798094735&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;data&quot; : {
        &quot;userId&quot;           : 1,
        &quot;userProfileImage&quot; : &quot;userProfileImage1&quot;,
        &quot;postings&quot;         : [{
            &quot;postingId&quot;        : 1,
            &quot;postingContent&quot;   : &quot;samplePostingContent1&quot;
        },{
            &quot;postingId&quot;        : 2,
            &quot;postingContent&quot;   : &quot;samplePostingContent2&quot;
        },{
            &quot;postingId&quot;        : 3,
            &quot;postingContent&quot;   : &quot;samplePostingContent3&quot;
        }]
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data 안에 유저id와 프로필이미지하고 postings를 주는데, postings에 해당 유저의 포스팅 객체들이 배열로 들어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 어떻게하지.........&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  JSON_ARRAYAGG, JSON_OBJECT&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html#function_json-arrayagg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html#function_json-arrayagg&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664801116245&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; SELECT o_id, attribute, value FROM t3;
+------+-----------+-------+
| o_id | attribute | value |
+------+-----------+-------+
|    2 | color     | red   |
|    2 | fabric    | silk  |
|    3 | color     | green |
|    3 | shape     | square|
+------+-----------+-------+
4 rows in set (0.00 sec)

mysql&amp;gt; SELECT o_id, JSON_ARRAYAGG(attribute) AS attributes
    -&amp;gt; FROM t3 GROUP BY o_id;
+------+---------------------+
| o_id | attributes          |
+------+---------------------+
|    2 | [&quot;color&quot;, &quot;fabric&quot;] |
|    3 | [&quot;color&quot;, &quot;shape&quot;]  |
+------+---------------------+
2 rows in set (0.00 sec)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON_ARRAYAGG를 이용하면 제이슨요소가 담긴 1차원배열로 결과가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 안에 JSON_OBJECT(키, 밸류)를 이용하면 json_arrayagg에 담긴 요소를 객체로 만들 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1664800115870&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
      users.id as userId,
      users.profile_image as userProfileImage,
      JSON_ARRAYAGG(
        JSON_OBJECT(
          'postingId', postings.id,
          'postingContents', postings.contents
        )
      ) as postings
    FROM postings
    JOIN users ON users.id = postings.user_id
    WHERE users.id = 1
    GROUP BY users.id
  ;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 코드에 적용하면&lt;/p&gt;
&lt;pre id=&quot;code_1664801694236&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.get('/postings/user/1', async (req, res) =&amp;gt; {
    const data = await myDataSource.query(`
        SELECT
            users.id as userId,
            users.profile_image as userProfileImage,
            JSON_ARRAYAGG(
                JSON_OBJECT(
                    'postingId', postings.id,
                    'postingContents', postings.contents
                )
            ) as postings
        FROM postings
        JOIN users ON users.id = postings.user_id
        WHERE users.id = 1
        GROUP BY users.id
        ;`);
    res.status(200).json({data: data});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccKo1u/btrNAMArOsM/0rWxh5tpmDCx64E5uSss5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccKo1u/btrNAMArOsM/0rWxh5tpmDCx64E5uSss5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccKo1u/btrNAMArOsM/0rWxh5tpmDCx64E5uSss5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccKo1u%2FbtrNAMArOsM%2F0rWxh5tpmDCx64E5uSss5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;678&quot; height=&quot;570&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;Update&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;게시글&amp;nbsp;정보&amp;nbsp;수정&amp;nbsp;엔드포인트&amp;nbsp;요구&amp;nbsp;사항&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1. 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요. -&amp;gt; 포스팅중에 1번을 수정하는거니까 'postings/1'로 한다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;데이터베이스에&amp;nbsp;저장되어있는&amp;nbsp;1번&amp;nbsp;id&amp;nbsp;유저의&amp;nbsp;1번&amp;nbsp;id&amp;nbsp;게시글을&amp;nbsp;확인합니다.&amp;nbsp;이후&amp;nbsp;해당&amp;nbsp;내역의&amp;nbsp;content를&amp;nbsp;기존의&amp;nbsp;데이터와&amp;nbsp;다른&amp;nbsp;내용으로&amp;nbsp;수정하여&amp;nbsp;저장합니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3.&amp;nbsp;postingId가&amp;nbsp;1번인&amp;nbsp;게시물의&amp;nbsp;내용을&amp;nbsp;&amp;ldquo;기존과&amp;nbsp;다르게&amp;nbsp;수정한&amp;nbsp;내용입니다.&amp;rdquo;로&amp;nbsp;수정한다면,&amp;nbsp;데이터베이스에서&amp;nbsp;끌어와&amp;nbsp;http&amp;nbsp;response로&amp;nbsp;반환하는&amp;nbsp;데이터의&amp;nbsp;형태는&amp;nbsp;다음과&amp;nbsp;같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664802007155&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;data&quot; : {
        &quot;userId&quot;           : 1,
        &quot;userName&quot;         : &quot;weCode&quot;,
        &quot;postingId&quot;        : 1,
        &quot;postingContent&quot;   : &quot;기존과 다르게 수정한 내용입니다.&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1664805927831&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.patch('/posting/1', async (req, res) =&amp;gt; {
    const {contents} = req.body;
    await myDataSource.query(
        `UPDATE postings
        SET contents = ?
        WHERE id = 1;`, [contents]);

    const data = await myDataSource.query(
        `SELECT 
            postings.user_id AS userId,
            users.nickname AS userName,
            postings.id AS postingId,
            postings.contents AS postingContent
        FROM postings
        JOIN users ON users.id = postings.user_id
        WHERE postings.id = 1;
        `);
    res.status(200).json({data: data});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kXOiu/btrNzGgh71y/8lnoW02Vb1Cncim8MU2HhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kXOiu/btrNzGgh71y/8lnoW02Vb1Cncim8MU2HhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kXOiu/btrNzGgh71y/8lnoW02Vb1Cncim8MU2HhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkXOiu%2FbtrNzGgh71y%2F8lnoW02Vb1Cncim8MU2HhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;586&quot; height=&quot;468&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 배열로 감싸져서 나올까? select면 여러줄일수 있는데 내가 그냥 조건을 하나만 나올 조건으로 정해논거라서?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; const [data] = await myDataSource.query(...)하면 알맹이만 data에 들어간다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zy36U/btrNIKVXvai/Oa0h4Ola8L9t0IyKWnOKG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zy36U/btrNIKVXvai/Oa0h4Ola8L9t0IyKWnOKG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zy36U/btrNIKVXvai/Oa0h4Ola8L9t0IyKWnOKG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZy36U%2FbtrNIKVXvai%2FOa0h4Ola8L9t0IyKWnOKG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;725&quot; height=&quot;195&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;Delete&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;게시글&amp;nbsp;삭제&amp;nbsp;API&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1. 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요. -&amp;gt; postings/6으로 해서 6번 게시글 삭제&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2. 데이터가 삭제 될 때에 알맞는 http 상태코드를 반환해주세요. -&amp;gt; 204: 주로 delete메소드 요청이 성공했을때&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3.&amp;nbsp;http&amp;nbsp;response로&amp;nbsp;반환하는&amp;nbsp;JSON&amp;nbsp;데이터의&amp;nbsp;형태는&amp;nbsp;다음과&amp;nbsp;같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664806472865&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;message&quot; : &quot;postingDeleted&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1664806995800&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.delete('/postings/6', async (req, res) =&amp;gt; {
    await myDataSource.query(
        `DELETE FROM postings
        WHERE id = 6;`);
    res.status(204).json({message: &quot;postingDeleted&quot;});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;489&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xWMz4/btrNDVqfygP/gnjppEpWzHGT3YKdumOXGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xWMz4/btrNDVqfygP/gnjppEpWzHGT3YKdumOXGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xWMz4/btrNDVqfygP/gnjppEpWzHGT3YKdumOXGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxWMz4%2FbtrNDVqfygP%2FgnjppEpWzHGT3YKdumOXGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;489&quot; height=&quot;268&quot; data-origin-width=&quot;489&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메세지 보냈는데 왜 안나오지? 204라서?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/el3ThN/btrNzIE5BPN/k7gLAzgSWFjFDKHyD3oAf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/el3ThN/btrNzIE5BPN/k7gLAzgSWFjFDKHyD3oAf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/el3ThN/btrNzIE5BPN/k7gLAzgSWFjFDKHyD3oAf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fel3ThN%2FbtrNzIE5BPN%2Fk7gLAzgSWFjFDKHyD3oAf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;729&quot; height=&quot;409&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;409&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제는 잘 됐다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/128</guid>
      <comments>https://ginghambagle.tistory.com/128#entry128comment</comments>
      <pubDate>Tue, 4 Oct 2022 00:25:01 +0900</pubDate>
    </item>
    <item>
      <title>node.js | 인스타그램: 서버-db연결, 회원가입</title>
      <link>https://ginghambagle.tistory.com/127</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;비밀번호 암호화가 없는 회원가입&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;프로젝트 생성&lt;/u&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1664791068055&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkdir westagram-node
cd westagram-node
npm init -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;초기설정&lt;/u&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Express 설치 / 적용&lt;/li&gt;
&lt;li&gt;nodemon 설치 / 적용&lt;/li&gt;
&lt;li&gt;cors 설치 / 적용&lt;/li&gt;
&lt;li&gt;dotenv 설치 / 환경 변수 적용&lt;/li&gt;
&lt;li&gt;morgan 설치 / 적용&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1664791743543&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install express
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;morgan은 http요청과 에러를 기록해주는 미들웨어라고 한다. 아직 사용법을 모르겠으니 일단 설치만 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;모든 cors 요청 허용하는법&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664792633476&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const cors = require('cors');

const app = express();
app.use(cors());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;typeorm-db연결&lt;/u&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1664792329980&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install mysql2
npm install typeorm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664792703861&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// .env
TYPEORM_CONNECTION = mysql
TYPEORM_HOST = 127.0.0.1
TYPEORM_PORT = 3306
TYPEORM_USERNAME = root
TYPEORM_PASSWORD = 비밀번호
TYPEORM_DATABASE = db이름
TYPEORM_LOGGING = TRUE

// app.js
require('dotenv').config();
const http = require('http');
const express = require('express');
const cors = require('cors');
const { DataSource } = require('typeorm');

const myDataSource = new DataSource({
    type: process.env.TYPEORM_CONNECTION,
    host: process.env.TYPEORM_HOST,
    port: process.env.TYPEORM_PORT,
    username: process.env.TYPEORM_USERNAME,
    password: process.env.TYPEORM_PASSWORD,
    database: process.env.TYPEORM_DATABASE
});

myDataSource.initialize().then(() =&amp;gt; {
    console.log(&quot;Data Source has been initialized&quot;)
    }).catch(() =&amp;gt; {
    console.log(&quot;Database initiate fail&quot;)
    })

const app = express();
app.use(express.json());
app.use(cors()); // 모든 cors요청 허용

const server = http.createServer(app);
server.listen(8000, () =&amp;gt; {console.log(&quot;서버켜짐&quot;);});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;258&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lhnzh/btrNEwRg2EB/yxzgwHIB4dglaA8IqyAgek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lhnzh/btrNEwRg2EB/yxzgwHIB4dglaA8IqyAgek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lhnzh/btrNEwRg2EB/yxzgwHIB4dglaA8IqyAgek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLhnzh%2FbtrNEwRg2EB%2FyxzgwHIB4dglaA8IqyAgek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;258&quot; height=&quot;59&quot; data-origin-width=&quot;258&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;회원가입&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;알맞은&amp;nbsp;API&amp;nbsp;호출&amp;nbsp;URL을&amp;nbsp;설정하여서&amp;nbsp;클라이언트와(httpie/postman)&amp;nbsp;통신을&amp;nbsp;성공해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - /users : 유저관련된 api이기때문에&lt;br /&gt;2. 알맞은 http 메소드를 선정하여서 유저의 정보를 백엔드 서버에 전달해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - post : body에 담긴 내용으로 데이터를 생성/수정할때 사용&lt;br /&gt;3. 데이터가 생성됐을 때에 알맞는 http 상태코드를 반환해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 201 : post요청에 따라 백엔드 서버에 데이터가 잘 생성/수정되었을때 코드&lt;br /&gt;5. http response로 반환하는 JSON 데이터의 형태는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664793248711&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        {
          &quot;message&quot; : &quot;userCreated&quot;
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원 테이블 구조&lt;/p&gt;
&lt;pre id=&quot;code_1664793504962&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; desc users;
+---------------+---------------+------+-----+-------------------+-------------------+
| Field         | Type          | Null | Key | Default           | Extra             |
+---------------+---------------+------+-----+-------------------+-------------------+
| id            | int           | NO   | PRI | NULL              | auto_increment    |
| email         | varchar(100)  | NO   | UNI | NULL              |                   |
| nickname      | varchar(50)   | YES  |     | NULL              |                   |
| password      | varchar(300)  | NO   |     | NULL              |                   |
| profile_image | varchar(3000) | YES  |     | NULL              |                   |
| created_at    | datetime      | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+---------------+---------------+------+-----+-------------------+-------------------+&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;id, created_at은 db에서 자동으로 값을 할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664793908469&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app.js
app.post('/users', async (req, res) =&amp;gt; {
    const {email, nickname, password, profileImage} = req.body;
    // 쿼리를 날리는건 비동기식으로 처리되는데 쿼리를 실행한 후 응답을 해줘야 하니까 async await를 썼다.
    await myDataSource.query(
        `INSERT INTO users (email, nickname, password, profile_image)
        VALUES (?, ?, ?, ?)`
        , [email, nickname, password, profileImage]);
    
    res.status(201).json({&quot;message&quot; : &quot;userCreated&quot;});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필수값인 email, password만 넣어서 회원가입을 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdBFS9/btrNANsuJcm/5NsyNMwr274sZybe8HIwsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdBFS9/btrNANsuJcm/5NsyNMwr274sZybe8HIwsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdBFS9/btrNANsuJcm/5NsyNMwr274sZybe8HIwsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdBFS9%2FbtrNANsuJcm%2F5NsyNMwr274sZybe8HIwsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;385&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ysEeQ/btrNB4Op2EE/1F9aYPDo7l4nyGkLTLOfI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ysEeQ/btrNB4Op2EE/1F9aYPDo7l4nyGkLTLOfI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ysEeQ/btrNB4Op2EE/1F9aYPDo7l4nyGkLTLOfI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FysEeQ%2FbtrNB4Op2EE%2F1F9aYPDo7l4nyGkLTLOfI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;933&quot; height=&quot;376&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 잘 들어온 것을 확인할 수 있다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/127</guid>
      <comments>https://ginghambagle.tistory.com/127#entry127comment</comments>
      <pubDate>Mon, 3 Oct 2022 19:52:34 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 | functools.wraps</title>
      <link>https://ginghambagle.tistory.com/126</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1차프로젝트때 로그인 데코레이터에 붙어있던 @wraps&lt;/p&gt;
&lt;pre id=&quot;code_1664787079987&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# core/utils.py
def accessCkeck(func):
    def wrapper(self, request, *args, **kwargs):
        ...
        return func(self, request, *args, **kwargs)
    return wrapper

# carts/views.py
...
class CartView(View):
    @accessCkeck
    def post(self, request):
    &quot;&quot;&quot;carts에 post요청이 오면 카트생성&quot;&quot;&quot; # docstring추가
        ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 2차때 써봤는데 정확히 무슨 역할을 하는건지 알아보지 않고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고링크 글에서 다른 개발자와 협업할때 데코레이터를 만들거라면 사용하는게 좋다!는 말만 보고 사용했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번기회에 다시 알아봤다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;@wraps가 없을때&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CartView의 post함수를 가지고 쉘에서 실험을 해봤는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;accessCkeck함수의 wrapper에서 @wraps데코레이터를 떼고&lt;span&gt; CartView.post함수를 찍어보면&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664788206236&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from carts.views import CartView
&amp;gt;&amp;gt;&amp;gt; CartView.post
&amp;lt;function accessCkeck.&amp;lt;locals&amp;gt;.wrapper at 0x10515a320&amp;gt;
&amp;gt;&amp;gt;&amp;gt; CartView.post.__doc__ # .__doc__은 함수의 docstring을 보여준다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 CartView.post가 아닌 accessCkeck.&amp;lt;locals&amp;gt;.wrapper함수라고 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 post함수의 docstring도 읽지 못한다. (당연한건가 CartView.post에 달려있는걸 읽어야하는데 CartView.post자체를 못읽으니까?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;@wraps가 있을때&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 accessCkeck의 @wraps를 살리고 post함수와 독스트링을 찍어보면&lt;/p&gt;
&lt;pre id=&quot;code_1664788796545&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from carts.views import CartView
&amp;gt;&amp;gt;&amp;gt; CartView.post
&amp;lt;function CartView.post at 0x10729e3b0&amp;gt;
&amp;gt;&amp;gt;&amp;gt; CartView.post.__doc__
'carts에 post요청이 오면 카트생성'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 CartView.post로 잘 나오는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;결론&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 완전히 이해한 것은 아니지만!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데코레이터를 사용하면 데코레이터가 붙어있는 함수는 내부적으로 데코레이터의 wrapper로 인식되고 원래 어떤 함수인지는 알아볼수 없게 되는것 같다. 그래서 해당 함수에 달린 docstring을 읽을 수도 없게 되는것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*docstring: class, module, function, method의 첫 줄에 위치한, 개발된 기능을 사용하거나 개발에 기여하는 다른 개발자들의 이해를 돕기 위해 작성되는 주석&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 functools.wraps()를 데코레이터에 사용하면 이런 문제점들이 없어진다. 그래서 협업할 때 사용하는것이 좋은것 같은데, 사실 프로젝트때도 굳이 없어도 되는 기능이었고 그래서 지금도 완벽히 이해가 안가지만 언젠가 이해할수 있길.............&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@doondoony/python-functools-wraps&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@doondoony/python-functools-wraps&lt;/a&gt;&lt;/p&gt;</description>
      <category>Python</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/126</guid>
      <comments>https://ginghambagle.tistory.com/126#entry126comment</comments>
      <pubDate>Mon, 3 Oct 2022 18:34:52 +0900</pubDate>
    </item>
    <item>
      <title>node.js | express, TypeORM 적용한 CRUD API만들기 - 2 API작성</title>
      <link>https://ginghambagle.tistory.com/125</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;db연결, 서버만들기 초기설정&lt;/h4&gt;
&lt;pre id=&quot;code_1664699730004&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app.js
require('dotenv').config();   // db와 연결해서 typeorm사용하기위해 환경변수를 불러온다
const http = require('http');
const express = require('express');
const { DataSource } = require('typeorm');

const myDataSource = new DataSource({      // DataSource객체를 이용해서 typeorm과 db연결준비
    type: process.env.TYPEORM_CONNECTION,
    host: process.env.TYPEORM_HOST,
    port: process.env.TYPEORM_PORT,
    username: process.env.TYPEORM_USERNAME,
    password: process.env.TYPEORM_PASSWORD,
    database: process.env.TYPEORM_DATABASE
});

myDataSource.initialize().then(() =&amp;gt; {    // db연결. 연결후 확인 위해 console.log
    console.log(&quot;Data Source has been initialized&quot;)
    }).catch(() =&amp;gt; {
    console.log(&quot;Database initiate fail&quot;)
    })

const app = express();   // express를 실행해서 app에 담는다
app.use(express.json()); // 미들웨어 설정

const port = 8000;

const server = http.createServer(app); // app으로 서버를 만든다
server.listen(port, () =&amp;gt; {console.log(&quot;서버켜짐&quot;);}); //서버를 켜고 확인 위해 console.log&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 책정보 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'/books'로 post요청이 오면 body에 담긴 데이터로 책 정보를 생성한다(books테이블에 저장)&lt;/p&gt;
&lt;pre id=&quot;code_1664700159898&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app.js
app.post('/books', async (req, res) =&amp;gt; {
    const {title, description, coverImage} = req.body;

    await myDataSource.query(
        `INSERT INTO books(
            title, description, cover_image
            ) VALUES (?, ?, ?);
        `, [title, description, coverImage]
    );
    res.status(201).json({message: &quot;successfully created&quot;});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리를 날리는 비동기이다. 그래서 기다렸다가 다되면 응답해줄수있게 async await사용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPEPkl/btrNzIEgZzr/ImjVi5OwIgWtKDgPPTXkn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPEPkl/btrNzIEgZzr/ImjVi5OwIgWtKDgPPTXkn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPEPkl/btrNzIEgZzr/ImjVi5OwIgWtKDgPPTXkn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPEPkl%2FbtrNzIEgZzr%2FImjVi5OwIgWtKDgPPTXkn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;452&quot; height=&quot;397&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VG584/btrNwnHXRbw/1TIO3s5g8yFqbGBjWyYd41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VG584/btrNwnHXRbw/1TIO3s5g8yFqbGBjWyYd41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VG584/btrNwnHXRbw/1TIO3s5g8yFqbGBjWyYd41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVG584%2FbtrNwnHXRbw%2F1TIO3s5g8yFqbGBjWyYd41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;790&quot; height=&quot;126&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 요청을 cover_image로 보내고 받을때 coverImage로 받아서 데이터가 안들어감!..coverImage에 undefined가 할당됐다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 책+작가정보 조회&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'/books'에 get요청이 오면 책과 작가의 정보를 보내준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책-작가는 중간 테이블(books_authors)이 있는 다대다 관계이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxhRqy/btrNCgHkiaa/w6qZ21Iqw2e05Kr3JFIdi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxhRqy/btrNCgHkiaa/w6qZ21Iqw2e05Kr3JFIdi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxhRqy/btrNCgHkiaa/w6qZ21Iqw2e05Kr3JFIdi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxhRqy%2FbtrNCgHkiaa%2Fw6qZ21Iqw2e05Kr3JFIdi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;782&quot; height=&quot;478&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인용으로 데이터를 이렇게 넣어놓은 상황&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간테이블을 이용해서 books와 authors를 조인해서 데이터를 가져오면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1664707855813&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; select
    -&amp;gt; books.id, books.title, books.description, books.cover_image, authors.first_name, authors.last_name, authors.age
    -&amp;gt; from books_authors ba
    -&amp;gt; inner join authors on ba.author_id=authors.id
    -&amp;gt; inner join books on ba.book_id=books.id;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDC15Y/btrNwkkbk2u/LpEo2NfBpcUHsG3SQ2TfKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDC15Y/btrNwkkbk2u/LpEo2NfBpcUHsG3SQ2TfKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDC15Y/btrNwkkbk2u/LpEo2NfBpcUHsG3SQ2TfKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDC15Y%2FbtrNwkkbk2u%2FLpEo2NfBpcUHsG3SQ2TfKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;954&quot; height=&quot;221&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 sql문을 이용해서 get요청이 왔을때 테이블의 각 로우를 객체 형태로 보내주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1664709018408&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.get('/books', async(req, res) =&amp;gt; {
    await myDataSource.query(
        `SELECT books.id,
        books.title,
        books.description,
        books.cover_image,
        authors.first_name,
        authors.last_name,
        authors.age
        FROM books_authors ba
        INNER JOIN authors ON ba.author_id = authors.id
        INNER JOIN books ON ba.book_id = books.id
        `, (err, rows) =&amp;gt; {
            res.status(200).json(rows); //rows에는 각 로우들이 객체 형태로 들어있다. err을 프린트해보면 에러가 출력된다. 에러가 없으면 null
        }
    );
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;593&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8W9vW/btrNyF2hSRB/yO21JqTKamdeHB73x1TuSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8W9vW/btrNyF2hSRB/yO21JqTKamdeHB73x1TuSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8W9vW/btrNyF2hSRB/yO21JqTKamdeHB73x1TuSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8W9vW%2FbtrNyF2hSRB%2FyO21JqTKamdeHB73x1TuSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;593&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;593&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 책 정보 수정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'/books' 경로로 수정할 책 데이터를 바디에 담아 put 요청을 보내면 책 정보가 수정되도록 하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'UPDATE 테이블 SET 수정사항 WHERE 조건' 이용&lt;/p&gt;
&lt;pre id=&quot;code_1664710827285&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.put('/books', async (req, res) =&amp;gt; {
    const {title, description, coverImage, bookId} = req.body;

    await myDataSource.query(
        `UPDATE books
        SET
        title = ?,
        description = ?,
        cover_image = ?
        WHERE id = ?`,
        [title, description, coverImage, bookId]
    );
    res.status(201).json({message: &quot;successfully updated&quot;});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXCwn7/btrNxew2HmD/m6HJkzLbfFI233Gbkcmubk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXCwn7/btrNxew2HmD/m6HJkzLbfFI233Gbkcmubk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXCwn7/btrNxew2HmD/m6HJkzLbfFI233Gbkcmubk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXCwn7%2FbtrNxew2HmD%2Fm6HJkzLbfFI233Gbkcmubk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;464&quot; height=&quot;426&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RXD7u/btrNAyO8z9i/VwI48nVH7PKkbNSJaPcX01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RXD7u/btrNAyO8z9i/VwI48nVH7PKkbNSJaPcX01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RXD7u/btrNAyO8z9i/VwI48nVH7PKkbNSJaPcX01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRXD7u%2FbtrNAyO8z9i%2FVwI48nVH7PKkbNSJaPcX01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;772&quot; height=&quot;120&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;url주소를 바꾸는 작업을 한 결과.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;title은 not null조건이 있기 때문에 값을 넣지 않거나 null을 넣으면 에러가 난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 put은 일부가 아닌 전체 수정을 의미하는 http 메소드이기 때문에 모든 컬럼값을 가지고 요청을 보내도록 한다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/125</guid>
      <comments>https://ginghambagle.tistory.com/125#entry125comment</comments>
      <pubDate>Sun, 2 Oct 2022 20:50:11 +0900</pubDate>
    </item>
    <item>
      <title>node.js | express, TypeORM 적용한 CRUD API만들기 - 1 db(dbmate)</title>
      <link>https://ginghambagle.tistory.com/124</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 배운걸 종합해서 간단한 CRUD구현해보기&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  데이터베이스 테이블 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 생성&lt;/p&gt;
&lt;pre id=&quot;code_1664639380680&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; create database typeorm_prac character set utf8mb4 collate utf8mb4_general_ci;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;dbmate&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;db 변경 이력을 남겨서 관리하기 위한 파일을 migration파일이라고 하는데 이 migration파일들을 관리하는 프로그램중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;u&gt;설치&lt;/u&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1664639150907&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install dbmate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  npm으로 프로젝트 내부에 설치된 프로그램 실행하는법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm으로 dbmate를 설치하면 그냥 터미널에서는 dbmate명령어를 사용할 수 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;40&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vv4hv/btrNyFHvFXr/BsEcfUGD77gTn4f4UonNv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vv4hv/btrNyFHvFXr/BsEcfUGD77gTn4f4UonNv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vv4hv/btrNyFHvFXr/BsEcfUGD77gTn4f4UonNv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvv4hv%2FbtrNyFHvFXr%2FBsEcfUGD77gTn4f4UonNv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;40&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;40&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;npx&lt;/span&gt; 명령어를 사용하면 된다(poetry run과 같은 동작을 하는 명령어) 프로젝트 내부에서 프로그램을 돌린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm 5.2.0부터 자동설치..낮은버전이라면 수동으로 npx를 설치해서 사용 가능&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;170&quot; data-origin-height=&quot;34&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eFPmtu/btrNwo7ykBJ/FQnsvpQF9xSWlCA3vZvOkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eFPmtu/btrNwo7ykBJ/FQnsvpQF9xSWlCA3vZvOkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eFPmtu/btrNwo7ykBJ/FQnsvpQF9xSWlCA3vZvOkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeFPmtu%2FbtrNwo7ykBJ%2FFQnsvpQF9xSWlCA3vZvOkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;170&quot; height=&quot;34&quot; data-origin-width=&quot;170&quot; data-origin-height=&quot;34&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;u&gt;db연결&lt;/u&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;/i&gt;.env파일 안에 본인db에 맞춰 아래처럼 적어서 db와 연결한다&lt;/p&gt;
&lt;pre id=&quot;code_1664685906500&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DATABASE_URL=&quot;mysql://username:password@127.0.0.1:3306/database_name&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;u&gt;migration파일 생성&lt;/u&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1664639244012&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx dbmate new create_books_table
$ npx dbmate new create_authors_table
$ npx dbmate new create_books_authors_table&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pRcpC/btrNwCYYHoT/kHfpjRFz6FmZcQLswduis1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pRcpC/btrNwCYYHoT/kHfpjRFz6FmZcQLswduis1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pRcpC/btrNwCYYHoT/kHfpjRFz6FmZcQLswduis1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpRcpC%2FbtrNwCYYHoT%2FkHfpjRFz6FmZcQLswduis1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;629&quot; height=&quot;160&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btrufG/btrNzEogWtC/Slreq9CSWbg9DLJmLwy601/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btrufG/btrNzEogWtC/Slreq9CSWbg9DLJmLwy601/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btrufG/btrNzEogWtC/Slreq9CSWbg9DLJmLwy601/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtrufG%2FbtrNzEogWtC%2FSlreq9CSWbg9DLJmLwy601%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;355&quot; height=&quot;94&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 프로젝트 안에 db폴더가 만들어지고 그 안에 migrations폴더 안에 파일들이 생긴다.&lt;/p&gt;
&lt;pre id=&quot;code_1664641573149&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- migrate:up


-- migrate:down&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;migration 파일은 이렇게 생겼는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;migrate:up 아래는 적용할 sql문을 적어주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;migrate:down아래는 위에 적용한 sql문을 되돌리는 sql문을 적어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(테이블 생성을 했다면 테이블 삭제하는 sql문, 테이블 이름을 변경했다면 다시 이전 이름으로 변경하는sql문)&lt;/p&gt;
&lt;pre id=&quot;code_1664641973445&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# create_books_table.sql
-- migrate:up
CREATE TABLE books (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(100) NOT NULL,
    description VARCHAR(2000) NULL,
    cover_image VARCHAR(1000) NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- migrate:down
DROP TABLE books;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1664686180995&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# create_authors_table.sql
-- migrate:up
CREATE TABLE authors (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    age INT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- migrate:down
DROP TABLE authors;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1664686232781&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# create_books_authors_table.sql
-- migrate:up
CREATE TABLE books_authors (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    book_id INT NOT NULL,
    author_id INT NOT NULL,
    CONSTRAINT books_authors_book_id_fkey FOREIGN KEY (book_id) REFERENCES books (id) ON DELETE CASCADE,
    CONSTRAINT books_authors_author_id_fkey FOREIGN KEY (author_id) REFERENCES authors (id) ON DELETE CASCADE
);

-- migrate:down
DROP TABLE books_authors;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;u&gt;migrate&lt;/u&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이그레이션 파일을 db에 실제로 적용하는 작업&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/412Y9/btrNAMGiSpZ/9kbJAKNAYpK6h5er3JXe6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/412Y9/btrNAMGiSpZ/9kbJAKNAYpK6h5er3JXe6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/412Y9/btrNAMGiSpZ/9kbJAKNAYpK6h5er3JXe6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F412Y9%2FbtrNAMGiSpZ%2F9kbJAKNAYpK6h5er3JXe6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;74&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;74&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1664686286662&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx dbmate up&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FfM40/btrNzF1NLRw/xTQrJga4WMBTq7MPvDKSRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FfM40/btrNzF1NLRw/xTQrJga4WMBTq7MPvDKSRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FfM40/btrNzF1NLRw/xTQrJga4WMBTq7MPvDKSRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFfM40%2FbtrNzF1NLRw%2FxTQrJga4WMBTq7MPvDKSRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;405&quot; height=&quot;82&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uWHq9/btrNyDXqBOD/sZWVV3mi7UestUGNCQpThK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uWHq9/btrNyDXqBOD/sZWVV3mi7UestUGNCQpThK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uWHq9/btrNyDXqBOD/sZWVV3mi7UestUGNCQpThK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuWHq9%2FbtrNyDXqBOD%2FsZWVV3mi7UestUGNCQpThK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;136&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;schema.sql은 migration을 통해 데이터베이스에 생긴 변화를 모두 기록하는 파일.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6adT4/btrNyE278cw/or4smMRokY44Mt1QfDQDfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6adT4/btrNyE278cw/or4smMRokY44Mt1QfDQDfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6adT4/btrNyE278cw/or4smMRokY44Mt1QfDQDfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6adT4%2FbtrNyE278cw%2For4smMRokY44Mt1QfDQDfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;914&quot; height=&quot;392&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/124</guid>
      <comments>https://ginghambagle.tistory.com/124#entry124comment</comments>
      <pubDate>Sun, 2 Oct 2022 14:02:03 +0900</pubDate>
    </item>
    <item>
      <title>구방문방구 | 리팩토링: 상품리스트 모듈화</title>
      <link>https://ginghambagle.tistory.com/123</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 코드를 쳐다보고있는데 메인페이지와 카테고리별 상품 페이지의 리스트 만드는 코드가 완전히 똑같은걸 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연함. 메인페이지의 상품 리스트는 전체상품에서 필터링(신상품, 친환경, 베스트)된 리스트를 보여주는 것이기 때문...&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✏️ 메인페이지 뷰(수정전)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKPhmp/btrNv9bBM8P/78X9SeuiCiXrZUJ3ImsR91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKPhmp/btrNv9bBM8P/78X9SeuiCiXrZUJ3ImsR91/img.png&quot; data-alt=&quot;메인페이지 신상품 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKPhmp/btrNv9bBM8P/78X9SeuiCiXrZUJ3ImsR91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKPhmp%2FbtrNv9bBM8P%2F78X9SeuiCiXrZUJ3ImsR91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1422&quot; height=&quot;660&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;660&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메인페이지 신상품 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1664627685533&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MainPageView(View):
    def get(self, request):
        def get_list(products):
            product_list =  [{
                'id'      : product.id,
                'name'    : product.name,
                'price'   : product.price,
                'is_green': product.is_green,
                'is_best' : product.is_best,
                'images'  : [{
                    'id' : image.id,
                    'url': image.url
                    } for image in product.productimage_set.all()]
            } for product in products]
            
            return product_list

        new_products   = Product.objects.all().prefetch_related('productimage_set').order_by('-created_at')[:8]
        best_products  = Product.objects.filter(is_best = True).prefetch_related('productimage_set').order_by('-created_at')[:8] 
        green_products = Product.objects.filter(is_green = True).prefetch_related('productimage_set').order_by('-created_at')[:8]

        return JsonResponse({
            'new_products'  : get_list(new_products),
            'best_products' : get_list(best_products),
            'green_products': get_list(green_products)}, status=200)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인페이지에서는 같은 리스트 세 개를 만들어야 해서 get_list라는 함수를 만들어서 활용했었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✏️ 카테고리별 페이지 뷰(수정전)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1425&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kKQSL/btrNyFHoxnD/r2ag4S9AWl0pDOUR49D5f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kKQSL/btrNyFHoxnD/r2ag4S9AWl0pDOUR49D5f0/img.png&quot; data-alt=&quot;전체 카테고리 상품 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kKQSL/btrNyFHoxnD/r2ag4S9AWl0pDOUR49D5f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkKQSL%2FbtrNyFHoxnD%2Fr2ag4S9AWl0pDOUR49D5f0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1425&quot; height=&quot;655&quot; data-origin-width=&quot;1425&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;전체 카테고리 상품 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1664627730292&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ProductListView(View):
    def get(self, request, category_id):
        try:
            ...
            products_data = [{
                    'id'      : product.id,
                    'name'    : product.name,
                    'price'   : product.price,
                    'is_green': product.is_green,
                    'is_best' : product.is_best,
                    'images'  : [{
                        'id' : image.id,
                        'url': image.url
                        } for image in product.productimage_set.all()]
                } for product in products]

            return JsonResponse({
                'category_data': category_data,
                'products_data': products_data}, status=200)
            ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상품 리스트 페이지에서도 완전히 같은 로직으로 변수명까지 같았는데 왜 몰랐을까~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 MainPageView의 get_list함수를 core/utils에 옮겨서 ProductListView에서도 사용할 수 있도록 만들었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  수정후&lt;/h4&gt;
&lt;pre id=&quot;code_1664629447840&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# core/utils.py
...
def get_product_list(products):
    product_list =  [{
        'id'      : product.id,
        'name'    : product.name,
        'price'   : product.price,
        'is_green': product.is_green,
        'is_best' : product.is_best,
        'images'  : [{
            'id' : image.id,
            'url': image.url
            } for image in product.productimage_set.all()]
    } for product in products]
    
    return product_list&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1664629604220&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# products/views.py
...
from core.utils import get_product_list

class MainPageView(View):
    def get(self, request):
        new_products   = Product.objects.all().prefetch_related('productimage_set').order_by('-created_at')[:8]
        best_products  = Product.objects.filter(is_best = True).prefetch_related('productimage_set').order_by('-created_at')[:8] 
        green_products = Product.objects.filter(is_green = True).prefetch_related('productimage_set').order_by('-created_at')[:8]

        return JsonResponse({
            'new_products'  : get_product_list(new_products),
            'best_products' : get_product_list(best_products),
            'green_products': get_product_list(green_products)}, status=200)

class ProductListView(View):
    def get(self, request, category_id):
        try:
            ...
            products = products.prefetch_related('productimage_set').order_by(sort_by[request.GET.get('sorting', None)])[ offset : offset + limit ]

            products_data = get_product_list(products)

            return JsonResponse({
                'category_data': category_data,
                'products_data': products_data}, status=200)
        ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;테스트&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;623&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8XkYi/btrNxdRTc4m/qtaNfpPARZoY6DZtlpSjoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8XkYi/btrNxdRTc4m/qtaNfpPARZoY6DZtlpSjoK/img.png&quot; data-alt=&quot;메인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8XkYi/btrNxdRTc4m/qtaNfpPARZoY6DZtlpSjoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8XkYi%2FbtrNxdRTc4m%2FqtaNfpPARZoY6DZtlpSjoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;623&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;623&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;621&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biZ9GQ/btrNvNs5yI0/6w6QylQb9TxV4zG4VCcEf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biZ9GQ/btrNvNs5yI0/6w6QylQb9TxV4zG4VCcEf0/img.png&quot; data-alt=&quot;전체&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biZ9GQ/btrNvNs5yI0/6w6QylQb9TxV4zG4VCcEf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiZ9GQ%2FbtrNvNs5yI0%2F6w6QylQb9TxV4zG4VCcEf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;849&quot; height=&quot;621&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;621&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;전체&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TbH8k/btrNzFNVLso/K5lcI97NOZYc2nvDttKbn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TbH8k/btrNzFNVLso/K5lcI97NOZYc2nvDttKbn0/img.png&quot; data-alt=&quot;2번 카테고리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TbH8k/btrNzFNVLso/K5lcI97NOZYc2nvDttKbn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTbH8k%2FbtrNzFNVLso%2FK5lcI97NOZYc2nvDttKbn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;845&quot; height=&quot;638&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2번 카테고리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>wecode</category>
      <category>구방문방구</category>
      <category>리팩토링</category>
      <category>배민문방구</category>
      <category>프로젝트</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/123</guid>
      <comments>https://ginghambagle.tistory.com/123#entry123comment</comments>
      <pubDate>Sat, 1 Oct 2022 22:11:34 +0900</pubDate>
    </item>
    <item>
      <title>node.js | TypeORM 적용하기</title>
      <link>https://ginghambagle.tistory.com/122</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;TypeORM의 풀링(데이터베이스 연결기능)과 raw query이용하기, 데이터베이스는 mysql사용&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  TypeORM설치&lt;/h4&gt;
&lt;pre id=&quot;code_1664440347280&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install mysql2  # typeorm-mysql 연동을 도와주는 드라이버
npm install typeorm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeorm을 먼저 설치하면 ER_NOT_SUPPORTED_AUTH_MODE에러가 날 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mysql2먼저 설치하기!&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  dotenv 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 관련 환경변수를 관리하기 위해 dotenv를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;dotenv 설치&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664440932344&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install dotenv #dotenv 설치&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;프로젝트 루트경로에 .env파일 생성후 환경변수 저장&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664441469796&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// .env파일
TYPEORM_CONNECTION = mysql
TYPEORM_HOST = 127.0.0.1
TYPEORM_USERNAME = root
TYPEORM_PASSWORD = 비밀번호
TYPEORM_DATABASE = typeorm_prac
TYPEORM_PORT = 3306
TYPEORM_LOGGING = TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경변수는 string으로 들어가는데 =뒤에는 전부 &quot;&quot;를 붙이거나 전부 안붙여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;typeorm_prac데이터베이스는 미리 만들어놓기&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664441547023&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; create database typeorm_prac character set utf8mb4 collate utf8mb4_general_ci;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;환경변수 불러오기&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.env에 저장해놓은 프로젝트 환경변수를 사용하기 위해 불러온다.&lt;/p&gt;
&lt;pre id=&quot;code_1664441772256&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app.js
const dotenv = require('dotenv');
dotenv.config(); // 아니면 한줄로 require('dotenv').config();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.log(process.env); 로 잘 불러오는지 확인해볼 수 있다. 내 컴퓨터 내 환경변수와 방금 추가한 프로젝트 내부 환경변수를 전부 불러온다. 제대로 되지 않았다면 전역변수만 불러옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(process객체는 node.js의 기본 글로벌 객체이다. require없이 모든 모듈에 접근이 가능하다.그중 환경변수가 담겨있는 .env객체에 접근해서 환경변수를 가져왔다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  TypeORM-DataSource로 db와 앱 연결&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;환경변수 이용해서 typeorm-db연결&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeorm의 DataSource를 이용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1664443644465&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// db연결 환경세팅
const { DataSource } = require('typeorm');
const myDataSource = new DataSource({
    type: process.env.TYPEORM_CONNECTION,
    host: process.env.TYPEORM_HOST,
    port: process.env.TYPEORM_PORT,
    username: process.env.TYPEORM_USERNAME,
    password: process.env.TYPEORM_PASSWORD,
    database: process.env.TYPEORM_DATABASE
});
// 실제 연결은 initialize메소드 사용
myDataSource.initialize();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeorm의 DataSource는 애플리케이션 코드랑 데이터베이스를 연결시켜주는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DataSource를 이용해서 내가 사용할 db(아까 만든거)랑 연결이 되는 myDataSource라는 인스턴스를 만들고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스의 Initialize메소드를 이용하면 실제로 연결이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 잘 연결되었는지 확인하는법&lt;/p&gt;
&lt;pre id=&quot;code_1664604340430&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;myDataSource.initialize().then(()=&amp;gt;{
    console.log(&quot;success&quot;)
}).catch(()=&amp;gt;{
    console.log(&quot;fail&quot;)
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;133&quot; data-origin-height=&quot;37&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brtBOm/btrNvxw5tyN/6XkOJLaszsTgKZrhKeo5p1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brtBOm/btrNvxw5tyN/6XkOJLaszsTgKZrhKeo5p1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brtBOm/btrNvxw5tyN/6XkOJLaszsTgKZrhKeo5p1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrtBOm%2FbtrNvxw5tyN%2F6XkOJLaszsTgKZrhKeo5p1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;133&quot; height=&quot;37&quot; data-origin-width=&quot;133&quot; data-origin-height=&quot;37&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 연결이 되면 success, 아니면 fail이 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  쿼리 날려보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스와 연결된 myDataSource의 query메소드를 이용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1664605607794&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;myDataSource.query('SQL쿼리문');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;db조회&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 typeorm_prac에 아무 것도 없어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ginghambagle.tistory.com/118&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;저번에 만든 justgram데이터베이스&lt;/a&gt;에 연결을 하고 users테이블에 있는 데이터들을 가져와보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.env파일에서 연결 데이터베이스 이름을 바꿔주고&lt;/p&gt;
&lt;pre id=&quot;code_1664605706725&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app.js
myDataSource.initialize().then(()=&amp;gt;{
    console.log(&quot;success&quot;)
    const queryRes = myDataSource.query('select * from users'); //쿼리의 결과 (queryRes)는 비동기로 오기때문에
    queryRes.then((value) =&amp;gt; {   // 여기서 .then()이용
        console.log(value); //출력해서 확인해보기
    });
}).catch(()=&amp;gt;{
    console.log(&quot;fail&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;535&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vmXIY/btrNwntIr6Q/TggX7iq3LBl5tcNTPH85ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vmXIY/btrNwntIr6Q/TggX7iq3LBl5tcNTPH85ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vmXIY/btrNwntIr6Q/TggX7iq3LBl5tcNTPH85ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvmXIY%2FbtrNwntIr6Q%2FTggX7iq3LBl5tcNTPH85ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;402&quot; height=&quot;535&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;535&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;u&gt;데이터입력&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 입력은 보통 요청으로 오는 값을 가지고 입력하게 되는데 변수를 넣어주려면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.query()의 괄호 안에 백틱``으로 쿼리문을 적고 입력값을 ?로 한다. 그리고 뒤에다가 ,를 하고 배열로 값을 적어주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1664608082931&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;myDataSource(`SQL문, 변수는 ?로 적는다`, [변수1, 변수2,...]);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1664606966248&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;myDataSource.initialize().then(()=&amp;gt;{
    console.log(&quot;success&quot;);
    const nickname = &quot;테스트&quot;;
    const email = &quot;test@test.com&quot;;
    const password = &quot;testpassword&quot;;

    myDataSource.query(`
    insert into users (email, nickname, password)
    values (?, ?, ?)`,
    [nickname, email, password])
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V95yW/btrNwFnnA7h/HlGCIk7j3kbavDzlL7nlg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V95yW/btrNwFnnA7h/HlGCIk7j3kbavDzlL7nlg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V95yW/btrNwFnnA7h/HlGCIk7j3kbavDzlL7nlg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV95yW%2FbtrNwFnnA7h%2FHlGCIk7j3kbavDzlL7nlg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;941&quot; height=&quot;170&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/122</guid>
      <comments>https://ginghambagle.tistory.com/122#entry122comment</comments>
      <pubDate>Sat, 1 Oct 2022 16:14:14 +0900</pubDate>
    </item>
    <item>
      <title>npm install 패키지명 &amp;quot;--save&amp;quot;를 꼭 해야할까</title>
      <link>https://ginghambagle.tistory.com/121</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;강의 영상을 보는데 어디서는 npm install만 하고 어디서는 --save를 해야된다고 해서 찾아봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  패키지 이름 뒤에 --save를 붙였던 이유:&lt;/p&gt;
&lt;pre id=&quot;code_1664367973760&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install 패키지이름 --save&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm 5.0.0버전 이전에는 --save를 붙여야 package.json파일 dependencies에 설치한 패키지가 추가됐다.&lt;/p&gt;
&lt;pre id=&quot;code_1664368129450&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// package.json
{
    ...
    &quot;dependencies&quot;: {
    &quot;express&quot;: &quot;^4.18.1&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  하지만 npm 5.0.0 버전 이후로는 npm install과 npm install --save가 차이 없다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--save를 붙이지 않아도 기본적으로 package.json 파일 dependencies에 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm 버전 확인하기&lt;/p&gt;
&lt;pre id=&quot;code_1664438854759&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm -V

&amp;gt;&amp;gt;&amp;gt;npm@8.5.5 /usr/local/lib/node_modules/npm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 npm 버전은 8.5.5라서 npm install만 해도 package.json에 패키지가 추가될것같다.&lt;/p&gt;
&lt;pre id=&quot;code_1664439003313&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install express&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSUCVx/btrNoJQMr8H/XHs4YHRnwZNF5YvlwbQKYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSUCVx/btrNoJQMr8H/XHs4YHRnwZNF5YvlwbQKYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSUCVx/btrNoJQMr8H/XHs4YHRnwZNF5YvlwbQKYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSUCVx%2FbtrNoJQMr8H%2FXHs4YHRnwZNF5YvlwbQKYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;548&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json파일을 열어보면 dependencies에 express가 잘 추가돼 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  결론&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 버전의 npm(5.0.0 이상)에서는 npm install 까지만 해도 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/what-is-the-meaning-of-save-for-npm-install/#:~:text=%E2%80%93save%20or%20%2DS%3A%20When,will%20not%20give%20desired%20results.&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.geeksforgeeks.org/what-is-the-meaning-of-save-for-npm-install/#:~:text=%E2%80%93save%20or%20%2DS%3A%20When,will%20not%20give%20desired%20results.&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>install</category>
      <category>npm</category>
      <category>save</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/121</guid>
      <comments>https://ginghambagle.tistory.com/121#entry121comment</comments>
      <pubDate>Fri, 30 Sep 2022 00:13:32 +0900</pubDate>
    </item>
    <item>
      <title>ORM(Object&amp;ndash;relational mapping)</title>
      <link>https://ginghambagle.tistory.com/120</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;ORM&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 프로그래밍(Object Oriented Programming)과 관계형 데이터베이스(Relational Database) 사이의 호환되지 않는 데이터를 변환하는 기술&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계형 데이터베이스의 2차원 테이블을 어플리케이션 Class에, 테이블 안에 저장된 행을 애플리케이션의 인스턴스에 각각 매핑해주는 역할&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;프로그래밍 언어를 사용해서 선언한 클래스와 인스턴스를 이용해서 데이터베이스 내부 자료 속성에 접근할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ORM 사용의 장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부수적인 코드가 사라지면서 개발의 생산성이 향상된다.&lt;/li&gt;
&lt;li&gt;ORM을 이용해서 문법 실수 없이 잘 짜여진 SQL 쿼리문을 사용할 수 있기 때문에 버그와 실수가 감소한다.&lt;/li&gt;
&lt;li&gt;개발자 친화적인 간결하고 직관적인 코드작성이 가능하다 -&amp;gt; 가독성 향상&lt;/li&gt;
&lt;li&gt;대부분의 ORM이 다양한 데이터베이스 시스템에 연결이 가능하기 때문에 데이터베이스 시스템이 아닌 데이터 객체에 집중해서 개발할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ORM 사용의 단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;미세한 수정이나 디버깅이 상대적으로 어려워진다.&lt;/li&gt;
&lt;li&gt;ORM에서 미리 선언해놓은 패턴에 따른 SQL 쿼리 명령만 사용할 수 있기 때문에 복잡한 쿼리문을 작성해야 할때 원래 의도보다 복잡한 쿼리가 만들어질 수 있다.&lt;/li&gt;
&lt;li&gt;DB에 직접 명령을 내리지 않고 중간단계를 한번 거치기 때문에 Raw쿼리문에 비해 실행속도가 느리다. (mysqlclient, mysql2같은 데이터베이스 드라이버를 한번 추상화하고, 이를 다시 추상화한다.)&lt;/li&gt;
&lt;li&gt;내부에서 실제로 어떤 쿼리를 실행하는지 파악하기 어렵다.&lt;/li&gt;
&lt;li&gt;사용하는 ORM에 따른 문법을 매번 익혀야 한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>기타</category>
      <category>ORM</category>
      <category>단점</category>
      <category>장점</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/120</guid>
      <comments>https://ginghambagle.tistory.com/120#entry120comment</comments>
      <pubDate>Thu, 29 Sep 2022 00:21:53 +0900</pubDate>
    </item>
    <item>
      <title>In-memory DB | Redis, Memcached</title>
      <link>https://ginghambagle.tistory.com/119</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;In-memory DB?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 저장을 위해 메인 메모리(RAM)에 주로 의존 하는 데이터베이스 관리 시스템. 디스크 기반 데이터베이스 관리 시스템과 대조된다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크 엑세스에 비해 메모리 엑세스 속도가 빠르기 때문에 응답시간이 중요한 어플리케이션에서 종종 in-memory database(IMDB)를 사용한다. 대용량 메모리를 처리할 수 있는 멀티 코어 프로세서가 등장하고 RAM의 가격이 저렴해지면서 IMDB는 특히 2000년대 중반 부터 데이터 분석 분야 에서 많은 주목을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 메모리에 주로 사용되는 RAM은 일반적으로 전원이 차단되면 내용이 지워지는 휘발성 기억 장치이다. 이런 RAM의 변동성이 인메모리 데이터베이스의 단점이 될 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  Redis &amp;amp; Memcached&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis와 Memcached는 많이 사용되는 오픈소스 IMDB의 종류이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Memcached는 단순함을 위해서 설계되었고, Redis는 다양한 범위에 효율적으로 사용할 수 있도록 많은 기능을 제공한다는 차이점이 있다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;공통점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;밀리초 미만의 응답시간 지원&lt;/li&gt;
&lt;li&gt;개발자의 사용 용이성: 구문적으로 사용하기 쉽고 어플리케이션에 통합하기 위해 최소한의 코드만 필요로 한다.&lt;/li&gt;
&lt;li&gt;데이터 파티셔닝: 수요가 증가하더라도 scale-out을 통해 더 많은 데이터를 잘 처리할 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;광범위한 프로그래밍 언어 지원: Java, Python, PHP, C, C++, C#, JavaScript, Node.js, Ruby, Go 등을 지원한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;차이점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✔️ Redis&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고급 데이터 구조: 문자열&amp;nbsp;외에도&amp;nbsp;목록,&amp;nbsp;집합,&amp;nbsp;정렬된&amp;nbsp;집합,&amp;nbsp;해시,&amp;nbsp;비트&amp;nbsp;배열&amp;nbsp;및&amp;nbsp;하이퍼로그를&amp;nbsp;지원한다.&lt;/li&gt;
&lt;li&gt;스냅샷: 특정 시점의 스냅샷으로 데이터를 디스크에 보관해서 기록하고 데이터 복구에 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;복제: 복제본을 여러개 생성해서 데이터베이스 읽기를 확장할 수 있다.&lt;/li&gt;
&lt;li&gt;트랜잭션 지원&lt;/li&gt;
&lt;li&gt;채팅방, 실시간 댓글창, 소셜미디어 피드등에 사용할 수 있는 패턴매치 sub/pub메세징을 지원한다.&lt;/li&gt;
&lt;li&gt;루아스크립팅: 어플리케이션을 단순화하고 성능을 높일 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;지리정보 : 대규모 지리데이터를 실시간으로 처리하기 위한 명령이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✔️ Memcached&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;멀티스레드 구조: scale-up방식을 통해 컴퓨팅 용량을 확장해서 더 많은 작업을 처리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/elasticache/redis-vs-memcached/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://aws.amazon.com/ko/elasticache/redis-vs-memcached/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/In-memory_database#cite_note-3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/In-memory_database#cite_note-3&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/119</guid>
      <comments>https://ginghambagle.tistory.com/119#entry119comment</comments>
      <pubDate>Wed, 28 Sep 2022 18:38:35 +0900</pubDate>
    </item>
    <item>
      <title>LeetCode | 009. Palindrome Number</title>
      <link>https://ginghambagle.tistory.com/117</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 숫자가 뒤집었을때도 같은 숫자면 True, 아니면 False반환&lt;/p&gt;
&lt;pre id=&quot;code_1664208083724&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Input: x = 121
Output: true
Explanation: 121 reads as 121 from left to right and from right to left.

Input: x = -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;내 풀이&lt;/h4&gt;
&lt;pre id=&quot;code_1664208137124&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def isPalindrome(self, x):
        &quot;&quot;&quot;
        :type x: int
        :rtype: bool
        &quot;&quot;&quot;
        return list(reversed(str(x))) == list(str(x))
# Runtime: 104 ms, faster than 43.79% of Python online submissions for Palindrome Number.
# Memory Usage: 13.3 MB, less than 85.23% of Python online submissions for Palindrome Number.
        return str(x) == str(x)[::-1]
# Runtime: 66 ms, faster than 84.25% of Python online submissions for Palindrome Number.
# Memory Usage: 13.5 MB, less than 35.99% of Python online submissions for Palindrome Number.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reversed를 활용하기 위해 x를 문자열로 바꾸고 reversed함수를 활용했는데 스트링을 reversed하면 거꾸로 된 스트링이 반환되는 게 아니라 reversed object가 반환된다. 그래서 이걸 다시 리스트로 바꾸고, 비교를 위해 스트링으로 바꾼 x를 리스트로 바꿔서 비교를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트링을 인덱스 활용해서 거꾸로 돌릴 수 있어서 스트링으로 바꾼 x랑 그걸 거꾸로 돌린거랑 비교해서 바로 리턴했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;다른풀이1&lt;/h4&gt;
&lt;pre id=&quot;code_1664257405622&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def isPalindrome(self, x):
        if x&amp;lt;0:
            return False

        inputNum = x
        newNum = 0
        while x&amp;gt;0:
            newNum = newNum * 10 + x%10
            x = x//10
        return newNum == inputNum
# Runtime: 129 ms, faster than 20.48% of Python online submissions for Palindrome Number.
# Memory Usage: 13.2 MB, less than 85.27% of Python online submissions for Palindrome Number.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수학적으로 접근한 풀이.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x가 0보다 작으면 무조건 False니까 처음에 if문으로 걸러주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x값을 따로 inputNum에 저장하고 나서 x를 뒤집은 수를 만드는 작업을 했다. print로 반복문을 돌때마다 찍어보면&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664258221659&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# x = 123454321일때
newNum:1, x:12345432
newNum:12, x:1234543
newNum:123, x:123454
newNum:1234, x:12345
newNum:12345, x:1234
newNum:123454, x:123
newNum:1234543, x:12
newNum:12345432, x:1
newNum:123454321, x:0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 나온다. 그래서 newNum과 아까 저장해둔 inputNum을 비교한 값을 리턴&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;다른풀이1-1&lt;/h4&gt;
&lt;pre id=&quot;code_1664257737535&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        if x &amp;lt; 0 or (x &amp;gt; 0 and x%10 == 0):   # if x is negative, return False. if x is positive and last digit is 0, that also cannot form a palindrome, return False.
            return False
	
        result = 0
        while x &amp;gt; result:
            result = result * 10 + x % 10
            x = x // 10

        return True if (x == result or x == result // 10) else False
# Runtime: 106 ms, faster than 41.91% of Python online submissions for Palindrome Number.
# Memory Usage: 13.1 MB, less than 96.99% of Python online submissions for Palindrome Number.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 방법인데 처음에 계산을 하지 않고 False로 바로 넘어가는 경우를 한가지 더 처리해줬고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복문을 위 방법의 반만 돌고 답을 찾을 수 있는 방법.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반만 돈 상태에서 둘을 비교해서 같으면 완전히 거꾸로 다 돌렸을때도 같은 값이니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 123454321 -&amp;gt; 하나씩 빼서 거꾸로 만들다가 1234 54321 일때 비교하면 나머지 값을 거꾸로 다 돌리기 전에 판단가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(자릿수가 홀수일 경우에 대비해서 true일 경우를 두가지로 나눴다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x = 123454321일때 print를 찍어보면&lt;/p&gt;
&lt;pre id=&quot;code_1664258664427&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;x: 12345432, result: 1
x: 1234543, result: 12
x: 123454, result: 123
x: 12345, result: 1234
x: 1234, result: 12345&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이만큼만 찍히고 바로 ture를 리턴한다 그래서 위 방법보다는 빠르게 결과가 나온다.&lt;/p&gt;</description>
      <category>TIL</category>
      <category>9번</category>
      <category>leetcode</category>
      <category>릿코드</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/117</guid>
      <comments>https://ginghambagle.tistory.com/117#entry117comment</comments>
      <pubDate>Wed, 28 Sep 2022 00:06:59 +0900</pubDate>
    </item>
    <item>
      <title>node.js | 인스타그램: 데이터베이스 구축</title>
      <link>https://ginghambagle.tistory.com/118</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2xmsE/btrNb49aMgx/LePkhZKwkPVTuHkVwa2DXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2xmsE/btrNb49aMgx/LePkhZKwkPVTuHkVwa2DXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2xmsE/btrNb49aMgx/LePkhZKwkPVTuHkVwa2DXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2xmsE%2FbtrNb49aMgx%2FLePkhZKwkPVTuHkVwa2DXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1066&quot; height=&quot;254&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 데이터베이스랑 연결한 서버를 만들기 위해 위 구조에 맞게 MySQL 데이터베이스 구축하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. mysql 접속&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664270293682&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql -u root -p
Enter password:&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. justgram 데이터베이스 만들고 접속&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664270345545&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; create database justgram character set utf8mb4 collate utf8mb4_general_ci;
mysql&amp;gt; use justgram&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 테이블 생성하기&lt;/h4&gt;
&lt;pre id=&quot;code_1664271721957&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; create table users(
    -&amp;gt; id int not null auto_increment primary key,
    -&amp;gt; email varchar(100) not null unique,
    -&amp;gt; nickname varchar(50),
    -&amp;gt; password varchar(300) not null,
    -&amp;gt; profile_image varchar(3000),
    -&amp;gt; created_at datetime default current_timestamp
    -&amp;gt; );

mysql&amp;gt; create table postings(
    -&amp;gt; id int auto_increment primary key,
    -&amp;gt; user_id int not null,
    -&amp;gt; contents varchar(2000),
    -&amp;gt; created_at datetime default current_timestamp,
    -&amp;gt; foreign key(user_id) references users(id) on delete cascade
    -&amp;gt; );
    
 mysql&amp;gt; create table posting_images(
    -&amp;gt; id int auto_increment primary key,
    -&amp;gt; posting_id int not null,
    -&amp;gt; image_url varchar(3000),
    -&amp;gt; created_at datetime default current_timestamp,
    -&amp;gt; foreign key(posting_id) references postings(id) on delete cascade
    -&amp;gt; );
    
 mysql&amp;gt; create table comments(
    -&amp;gt; id int auto_increment primary key,
    -&amp;gt; comment varchar(2000),
    -&amp;gt; posting_id int not null,
    -&amp;gt; user_id int not null,
    -&amp;gt; created_at datetime default current_timestamp,
    -&amp;gt; foreign key(posting_id) references postings(id) on delete cascade,
    -&amp;gt; foreign key(user_id) references users(id) on delete cascade
    -&amp;gt; );&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAAqIN/btrNb8YhnnW/DGX9gaaevhc0iw3qqZKrD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAAqIN/btrNb8YhnnW/DGX9gaaevhc0iw3qqZKrD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAAqIN/btrNb8YhnnW/DGX9gaaevhc0iw3qqZKrD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAAqIN%2FbtrNb8YhnnW%2FDGX9gaaevhc0iw3qqZKrD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;709&quot; height=&quot;786&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;786&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;not null 조건 추가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 테이블 created_at 컬럼에 not null조건을 넣지 않아서 추가했다.&lt;/p&gt;
&lt;pre id=&quot;code_1664359224389&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; alter table 테이블명
    -&amp;gt; modify column created_at datetime not null default current_timestamp;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ChGgx/btrNhPcVKa9/6ObOADNSBjj5zIfLT1kCN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ChGgx/btrNhPcVKa9/6ObOADNSBjj5zIfLT1kCN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ChGgx/btrNhPcVKa9/6ObOADNSBjj5zIfLT1kCN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FChGgx%2FbtrNhPcVKa9%2F6ObOADNSBjj5zIfLT1kCN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;714&quot; height=&quot;524&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. SQL &lt;span style=&quot;background-color: #dddddd;&quot;&gt;INSERT INTO&lt;/span&gt; 활용해서 테이블에 데이터 추가하기&lt;/h4&gt;
&lt;pre id=&quot;code_1664278946359&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; insert into users (email, nickname, password, profile_image)
    -&amp;gt; values (&quot;codeKim@justcode.co.kr&quot;, &quot;codeKim&quot;, &quot;c0DeK!m&quot;, &quot;http://profile_image_1.jpeg&quot;),
    -&amp;gt; (&quot;codeLee@justcode.co.kr&quot;, &quot;codeLee&quot;, &quot;C0dEL22&quot;, &quot;http://profile_image_2.jpeg&quot;),
    -&amp;gt; (&quot;codePark@justcode.co.kr&quot;, &quot;codePark&quot;, &quot;P@rkCOdE!&quot;, &quot;http://profile_image_3.jpeg&quot;),
    -&amp;gt; (&quot;codeChoi@justcode.co.kr&quot;, &quot;codeChoi&quot;, &quot;ChoiCodDE&quot;, &quot;http://profile_image_4.jpeg&quot;);

mysql&amp;gt; insert into postings (user_id, contents)
    -&amp;gt; values (1, &quot;작은 성공이 주는 성취감으로 하루를 마무리 할 수 있기를 ❣️&quot;),
    -&amp;gt; (1, &quot;오늘은 코딩하기 좋은날  &quot;),
    -&amp;gt; (2, &quot;db 모델링이 정말 재밌어요 ㅎㅎ&quot;),
    -&amp;gt; (2, &quot;어려워도 우린 결국 해낼겁니다.&quot;);

mysql&amp;gt; insert into posting_images (posting_id, image_url)
    -&amp;gt; values (1, &quot;http://posting_1_image_1.jpeg&quot;),
    -&amp;gt; (1, &quot;http://posting_1_image_2.jpeg&quot;),
    -&amp;gt; (2, &quot;http://posting_2_image_1.jpeg&quot;),
    -&amp;gt; (3, &quot;http://posting_3_image_1.jpeg&quot;),
    -&amp;gt; (3, &quot;http://posting_3_image_2.jpeg&quot;),
    -&amp;gt; (3, &quot;http://posting_3_image_3.jpeg&quot;),
    -&amp;gt; (4, &quot;http://posting_4_image_1.jpeg&quot;);
    
mysql&amp;gt; insert into comments (posting_id, comment, user_id)
    -&amp;gt; values (1, &quot;작은 성공이 모여 큰 성취가 되니까요!&quot;, 3),
    -&amp;gt; (4, &quot;같이 힘냅시다&quot;, 1),
    -&amp;gt; (2, &quot;햇살이 너무 좋아서 코딩하고 싶지 않아요&quot;, 2),
    -&amp;gt; (2, &quot;지금 비오는걸요&quot;, 4),
    -&amp;gt; (3, &quot;모델링 최고! 생각하는거 너무 재밌죠&quot;, 3),
    -&amp;gt; (4, &quot;언제나 길이 있기 마련입니다.&quot;, 1),
    -&amp;gt; (1, &quot;자다가 코딩하는 꿈꿀 것 같아요&quot;, 4);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFEQEA/btrNbYVVx34/s9BtZ413BVYuvb2HEJQ4xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFEQEA/btrNbYVVx34/s9BtZ413BVYuvb2HEJQ4xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFEQEA/btrNbYVVx34/s9BtZ413BVYuvb2HEJQ4xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFEQEA%2FbtrNbYVVx34%2Fs9BtZ413BVYuvb2HEJQ4xK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1035&quot; height=&quot;806&quot; data-origin-width=&quot;1035&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 테이블 join해서 데이터 확인해보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. users - postings&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664279788599&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; SELECT users.nickname, users.profile_image, postings.contents
    -&amp;gt; FROM users
    -&amp;gt; JOIN postings ON postings.user_id = users.id
    -&amp;gt; ;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OIsvI/btrNb49qQj4/pebAKikhlEYOPamz8GNuo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OIsvI/btrNb49qQj4/pebAKikhlEYOPamz8GNuo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OIsvI/btrNb49qQj4/pebAKikhlEYOPamz8GNuo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOIsvI%2FbtrNb49qQj4%2FpebAKikhlEYOPamz8GNuo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1060&quot; height=&quot;135&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; users테이블과 postings테이블을 외래키인 유저 아이디를 이용해서 inner join 한 결과에서 유저닉네임, 프로필이미지, 포스팅내용을 보는 sql문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. users - postings - comments&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664280088492&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; SELECT users.nickname, users.profile_image, postings.contents, comments.comment
    -&amp;gt; FROM users
    -&amp;gt; JOIN postings ON postings.user_id = users.id
    -&amp;gt; JOIN comments ON comments.posting_id = postings.id
    -&amp;gt; ;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwSoQN/btrM9R30veR/nZgg3oeYBzXNKYv4ESRBfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwSoQN/btrM9R30veR/nZgg3oeYBzXNKYv4ESRBfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwSoQN/btrM9R30veR/nZgg3oeYBzXNKYv4ESRBfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwSoQN%2FbtrM9R30veR%2FnZgg3oeYBzXNKYv4ESRBfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1349&quot; height=&quot;178&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; users - postings - comments 를 모두 join했다. 위의 결과에 posting별 comments까지 모두 조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 1번 &lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;users의 이름과, 1번 users의 profile_image, 1번 user가 남긴 posting, 해당 posting에 포함된 댓글, 그리고 포함된 posting_images까지 불러오고자 한다면 어떤 SQL를 작성해야할까요?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664280857953&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; Select users.nickname, users.profile_image, postings.contents, comments.comment, posting_images.image_url
    -&amp;gt; From users
    -&amp;gt; Join postings on postings.user_id = users.id
    -&amp;gt; Join comments on comments.posting_id = postings.id
    -&amp;gt; Join posting_images on posting_images.posting_id = postings.id
    -&amp;gt; Where users.id = 1
    -&amp;gt; ;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NsLDE/btrNa3QHu80/gj3A2kNxry8K5NRIQny1DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NsLDE/btrNa3QHu80/gj3A2kNxry8K5NRIQny1DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NsLDE/btrNa3QHu80/gj3A2kNxry8K5NRIQny1DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNsLDE%2FbtrNa3QHu80%2Fgj3A2kNxry8K5NRIQny1DK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1349&quot; height=&quot;137&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/118</guid>
      <comments>https://ginghambagle.tistory.com/118#entry118comment</comments>
      <pubDate>Tue, 27 Sep 2022 21:15:54 +0900</pubDate>
    </item>
    <item>
      <title>node.js | express로 서버 만들기 - 게시글 등록, 목록조회(DB x)</title>
      <link>https://ginghambagle.tistory.com/116</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt; 유저 데이터&lt;/p&gt;
&lt;pre id=&quot;code_1664203249109&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const users = [
    {
        id      : 1,
        name    : &quot;Rebekah Johnson&quot;,
        email   : &quot;Glover12345@gmail.com&quot;,
        password: &quot;123qwe&quot;,
    },
    {
        id      : 2,
        name    : &quot;Fabian Predovic&quot;,
        email   : &quot;Connell29@gmail.com&quot;,
        password: &quot;password&quot;,
    },
];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 게시글 데이터 형태&lt;/p&gt;
&lt;pre id=&quot;code_1664202628488&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const posts = [
    {
        id: 1,
        title: &quot;간단한 HTTP API 개발 시작!&quot;,
        content: &quot;Node.js에 내장되어 있는 http 모듈을 사용해서 HTTP server를 구현.&quot;,
        userId: 1,
    },
    {
        id: 2,
        title: &quot;HTTP의 특성&quot;,
        content: &quot;Request/Response와 Stateless!!&quot;,
        userId: 1,
    },
];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 게시글 리스트 응답 형태&lt;/p&gt;
&lt;pre id=&quot;code_1664202699617&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;data&quot; : [
    {
        &quot;userID&quot;           : 1,
        &quot;userName&quot;         : &quot;Rebekah Johnson&quot;
        &quot;postingId&quot;        : 1,
        &quot;postingTitle&quot;     : &quot;간단한 HTTP API 개발 시작!&quot;,
        &quot;postingContent&quot;   : &quot;Node.js에 내장되어 있는 http 모듈을 사용해서 HTTP server를 구현.&quot;
    },
    {  
        &quot;userID&quot;           : 2,
        &quot;userName&quot;         : &quot;Fabian Predovic&quot;
        &quot;postingId&quot;        : 2,
        &quot;postingTitle&quot;     : &quot;HTTP의 특성&quot;,
        &quot;postingContent&quot;   : &quot;Request/Response와 Stateless!!&quot;
    }
]
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 게시글 등록&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게시글등록은 앞에서 만든 &lt;a href=&quot;https://ginghambagle.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;회원가입&lt;/a&gt;이랑 로직이 똑같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post.js를 따로 만들어서 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;post.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664203316701&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const posts = [
    {
        id: 1,
        title: &quot;간단한 HTTP API 개발 시작!&quot;,
        content: &quot;Node.js에 내장되어 있는 http 모듈을 사용해서 HTTP server를 구현.&quot;,
        userId: 1,
    },
    {
        id: 2,
        title: &quot;HTTP의 특성&quot;,
        content: &quot;Request/Response와 Stateless!!&quot;,
        userId: 1,
    },
];

const createPost = (req, res) =&amp;gt; {
    const {id, title, content, userId} = req.body.data;
    posts.push({id, title, content, userId});
    res.json({massage: 'postCreated'});
};

module.exports = {createPost};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664203474874&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require('http');
const express = require('express');
const {createUser} = require('./user');
const {createPost} = require('./post');

const app = express();
app.use(express.json());

app.post('/signup', createUser);
app.post('/post', createPost);

const server = http.createServer(app);
server.listen(8000, () =&amp;gt; {});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 게시글 목록 조회&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게시글 목록은 그냥 posts배열을 리턴하면 되지만, 응답해줘야하는 데이터의 키가 다르고, 포스트 객체가 갖고 있지 않은 데이터인 유저의 이름(userName)도 넘겨줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;post.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664203894966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const {users} = require('./user')
const posts = [
    {
        id: 1,
        title: &quot;간단한 HTTP API 개발 시작!&quot;,
        content: &quot;Node.js에 내장되어 있는 http 모듈을 사용해서 HTTP server를 구현.&quot;,
        userId: 1,
    },
    ...
];

const createPost = (req, res) =&amp;gt; {
    ...
};

const getPosts = (req, res) =&amp;gt; {
    const data = posts.map((post) =&amp;gt; {
        const user = users.find((user) =&amp;gt; post.userId == user.id);
        return {
            userId: post.userId,
            userName: user.name,
            postingId: post.id,
            postingTitle: post.title,
            postingContent: post.content
        }
    } );
    res.json({data: data});
}

module.exports = {createPost, getPosts};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 포스트 객체의 키를 바꾸고, 유저이름까지 추가해서 리턴해주기 위해 map을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스트 객체가 가지고 있는 userId로 유저의 이름을 알아내기 위해 users 목록을 user.js에서 가져와서 find메서드를 통해 user의 id가 post의 userId와 같은 유저 객체를 user에 담아서 userName을 뽑아냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키 이름이 다 바뀌었기 때문에 나머지 데이터도 ...post를 사용하지 않고 알맞은 키를 새로 적어서 넣어줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664205693326&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require('http');
const express = require('express');
const {createUser} = require('./user');
const {createPost, getPosts} = require('./post');

const app = express();
app.use(express.json());

app.post('/signup', createUser);
app.post('/post', createPost);
app.get('/post', getPosts);

const server = http.createServer(app);
server.listen(8000, () =&amp;gt; {});&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;테스트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;post&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmX4MN/btrM8fWBG5y/e60yGH6KdvMGLnYP4rXoO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmX4MN/btrM8fWBG5y/e60yGH6KdvMGLnYP4rXoO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmX4MN/btrM8fWBG5y/e60yGH6KdvMGLnYP4rXoO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmX4MN%2FbtrM8fWBG5y%2Fe60yGH6KdvMGLnYP4rXoO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;647&quot; height=&quot;440&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;get&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;701&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BbaDM/btrM294VZ8j/6Ae1koZkibe6Jy88Zj5hEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BbaDM/btrM294VZ8j/6Ae1koZkibe6Jy88Zj5hEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BbaDM/btrM294VZ8j/6Ae1koZkibe6Jy88Zj5hEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBbaDM%2FbtrM294VZ8j%2F6Ae1koZkibe6Jy88Zj5hEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;809&quot; height=&quot;701&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>TIL</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/116</guid>
      <comments>https://ginghambagle.tistory.com/116#entry116comment</comments>
      <pubDate>Tue, 27 Sep 2022 00:23:39 +0900</pubDate>
    </item>
    <item>
      <title>node.js 개발툴 | nodemon으로 서버 변경사항 바로 적용하기</title>
      <link>https://ginghambagle.tistory.com/115</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;node.js로 서버 개발을 하면서 코드를 계속 수정하고 테스트하면서 변경사항을 확인해봐야 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node 명령어로 서버를 켜면 코드를 수정해도 변경사항이 반영되지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJcqEE/btrM7jZljve/uVP1AMCUbbm8GCVnzZpgxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJcqEE/btrM7jZljve/uVP1AMCUbbm8GCVnzZpgxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJcqEE/btrM7jZljve/uVP1AMCUbbm8GCVnzZpgxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJcqEE%2FbtrM7jZljve%2FuVP1AMCUbbm8GCVnzZpgxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;313&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 runserver는 파일을 수정하고 저장하면 자동으로 서버가 재시작되고 수정사항이 반영된다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 변경사항이 있을때마다 서버를 계속 껐다가 다시 켜야 하는데 nodemon을 사용하면 코드를 수정해서 저장할때마다 서버가 재시작 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. nodemon 설치&lt;/h4&gt;
&lt;pre id=&quot;code_1664190920259&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -g nodemon&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-g옵션으로 전역에 설치해서 다른 프로젝트에서도 사용 가능하도록 하기&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. nodemon 사용하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node 대신 nodemon명령어로 서버를 실행하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1664191103555&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nodemon 파일명&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwYPo7/btrM64uysWV/R0GVhk5kVhoS6YTmBCaQ50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwYPo7/btrM64uysWV/R0GVhk5kVhoS6YTmBCaQ50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwYPo7/btrM64uysWV/R0GVhk5kVhoS6YTmBCaQ50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwYPo7%2FbtrM64uysWV%2FR0GVhk5kVhoS6YTmBCaQ50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;351&quot; height=&quot;212&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일이 수정될 때마다 서버가 재가동된다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>node.js</category>
      <category>nodemon</category>
      <category>변경사항</category>
      <category>서버</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/115</guid>
      <comments>https://ginghambagle.tistory.com/115#entry115comment</comments>
      <pubDate>Tue, 27 Sep 2022 00:19:27 +0900</pubDate>
    </item>
    <item>
      <title>node.js | express로 서버 만들기 - 회원가입 엔드포인트 만들기(DB x)</title>
      <link>https://ginghambagle.tistory.com/114</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ginghambagle.tistory.com/113&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;저번에 만든 express로 만든 서버&lt;/a&gt;는 '/signup'으로 post요청이 들어오면 단순히 &quot;회원가입 완료!&quot;문자열을 응답으로 보내주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 &lt;b&gt;요청으로 온 데이터(회원정보)를 처리하는 법&lt;/b&gt;을 익히기 위해 회원가입 로직 변경해보기&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. user.js 작성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저 데이터를 users에 저장해주는 createUser함수를 만들어준다.&lt;/p&gt;
&lt;pre id=&quot;code_1664187654417&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 아직 데이터베이스는 활용하지 않고 배열 활용. 새 유저가 가입하면 이 배열에 저장시킬거.
const users = [
    {
        id: 1,
        name: &quot;김길동&quot;,
        email: &quot;gildong@gmail.com&quot;,
        password: &quot;pw123&quot;
    },
    {
        id: 2,
        name: &quot;홍코드&quot;,
        email: &quot;hong@gmail.com&quot;,
        password: &quot;hong123&quot;
    }
];

const createUser = (req, res) =&amp;gt; {
    // 요청 body: req.body 안의 data객체를 가져오는법(data라는 이름은 프론트가 주는 이름대로).이 데이터(객체)를 user에 저장
    const user = req.body.data; 
    console.log(user); // 받은 데이터 콘솔로 찍어서 확인

    users.push({
        id : user.id,
        name : user.name,
        email : user.email,
        password : user.password
    });
    console.log(users); // 잘 들어갔는지 확인

    res.json({massage: 'USER_CREATED'});
    // express를 이용하기때문에 JSON.stringify필요없이 응답객체의 json메소드 활용
}

module.exports = {createUser};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청의 body는 req객체 안의 body객체에 담겨있다. -&amp;gt; req.body로 꺼내서 쓸 수 있음(고정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 안의 유저 데이터를 꺼내서 쓰려면 req.body.data로 꺼낼 수 있다. 뒤의 data는 프론트엔드에서 data라는 키에 데이터를 담아서 줄 경우이다. 뒤의 이름은 바뀔 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* 구조분해할당&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664196483011&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// request.body
{
    &quot;data&quot;: {
        &quot;id&quot;: 3,
        &quot;name&quot;: &quot;테스트유저&quot;,
        &quot;email&quot;: &quot;test@test.com&quot;,
        &quot;password&quot;: &quot;1234&quot;
    }
}

// request.body.data
{
    &quot;id&quot;: 3,
    &quot;name&quot;: &quot;테스트유저&quot;,
    &quot;email&quot;: &quot;test@test.com&quot;,
    &quot;password&quot;: &quot;1234&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;request.body.data는 위의 형태가 되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;request.body.data의 키를 이용해서 아래처럼 구조분해할당을 한 후 user.id, user.name,...대신 id, name을 쓸 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1664196376867&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const createUser = (req, res) =&amp;gt; {
    // const user = req.body.data; 이걸 아래처럼 구조분해할당 한 후 
    const {id, name, email, password} = req.body.data;

    users.push({
        id : id,
        name : name,
        email : email,
        password : password
    }); // 이렇게만 넣어줘도 된다.
    res.json({massage: 'USER_CREATED'});
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* 자바스크립트 객체의 키-밸류가 같을 때&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키-밸류가 같으면 한번만 써줘도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1664196434828&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;users.push({
    id : id,
    name : name,
    email : email,
    password : password
});
// 아래와 위는 같은 코드
users.push({
        id,
        name,
        email,
        password
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* 수정된 createUser&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664197494165&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const createUser = (req, res) =&amp;gt; {
    const {id, name, email, password} = req.body.data; // 구조분해할당
    users.push({id, name, email, password}); // key-value가 같아서 한번만 써줌
    res.json({massage: &quot;userCreated&quot;})
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. serverWithExpress.js 코드 변경&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'/signup' url로 post요청이 오면 createUser를 실행하도록 코드를 변경해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1664188085416&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// createUser임포트 하고
const {createUser} = require('./user');
...
// app.post('/signup', (req, res) =&amp;gt; {res.json({message: '회원가입 완료!'})});
// 위의 코드를 아래와 같이 변경
app.post('/signup', createUser); // '/signup'url로 post요청이 오면 createUser실행
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664187991775&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 전체코드
const http = require('http');
const express = require('express');
const {sendProducts} = require('./sendProducts2');
const {createUser} = require('./user');

// express로 앱 생성
const app = express();
// 자바스크립트 객체들을 모두 json으로 변환하라고 미리 알려준다. JSON.stringify()를 쓰지 않아도 되도록.
app.use(express.json());

// express로 만든 앱에 해당 url로 get요청이 들어왔을시 이렇게 동작하겠다
// app.http메서드(url, 콜백함수)
app.get('/ping', (req, res) =&amp;gt; {
    res.json({message: '/ pong'});
});

app.post('/signup', createUser);
app.post('/login', (req, res) =&amp;gt; {res.json({message: '로그인 완료!'})});
app.get('/products', sendProducts);

// 원래는 http.createServer에 모든걸 다 넣어줬는데 위에서 분리를 다 시켜놓고 인자로 app만 준다.
const server = http.createServer(app);

server.listen(8000, () =&amp;gt; {
    console.log('server is listening on PORT 8000');
})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 요청 보내기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버를 켜고 postman으로 요청을 보내서 테스트 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pjh1F/btrM5QQ82Eo/wktvRDocuykowp22KMqHu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pjh1F/btrM5QQ82Eo/wktvRDocuykowp22KMqHu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pjh1F/btrM5QQ82Eo/wktvRDocuykowp22KMqHu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPjh1F%2FbtrM5QQ82Eo%2FwktvRDocuykowp22KMqHu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;741&quot; height=&quot;520&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mm25r/btrM64abb7b/dukvtsSLFxZNkYahCuy3Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mm25r/btrM64abb7b/dukvtsSLFxZNkYahCuy3Tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mm25r/btrM64abb7b/dukvtsSLFxZNkYahCuy3Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmm25r%2FbtrM64abb7b%2FdukvtsSLFxZNkYahCuy3Tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;563&quot; height=&quot;124&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.log로 body로 받은 데이터와, 해당 데이터를 가진 새로운 user가 users에 저장된 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <category>body</category>
      <category>node.js</category>
      <category>Request</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/114</guid>
      <comments>https://ginghambagle.tistory.com/114#entry114comment</comments>
      <pubDate>Mon, 26 Sep 2022 20:00:42 +0900</pubDate>
    </item>
    <item>
      <title>node.js | express 없이/express로 서버 만들기</title>
      <link>https://ginghambagle.tistory.com/113</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;express를 사용하는 이유를 알기 위해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;express 없이 서버를 만들어보고, 어떤점이 불편한지 알아보고, express로 서버를 만들어보자&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  express없이 서버 만들기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 프로젝트 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664128352287&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 프로젝트 폴더 만들고 이동
mkdir node-test
cd node-test
// 프로젝트 시작
npm init -y
// y옵션을 주면 기본값 설정으로 한번에 초기화 할 수 있다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. serverWithoutExpress.js 작성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버로 어떤 요청이 오면 메세지를 보내주도록 작성했다.&lt;/p&gt;
&lt;pre id=&quot;code_1664128150211&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// http통신을 하기위해 http모듈을 불러온다
const http = require('http');

// http의 createServer함수로 서버를 만들어서 server변수에 담아줌
const server = http.createServer((req, res) =&amp;gt; {
    // 요청이 오면 동작.
    console.log('request received');

    // 응답의 형태가 json이라는 것을 알려줌
    res.setHeader('Content-Type', 'application/json');
    // 응답으로 보내주는 데이터
    res.end(JSON.stringify({ message: &quot;Welcome to server! Http server without express&quot; }));
})
// 서버를 켜는 명령어 listen 8000번 포트에서 켠다.
server.listen(8000, () =&amp;gt; (
    // 서버가 켜지면 동작
    console.log(&quot;server is running on PORT 8000&quot;)
))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-1. 여러 api 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 url과 메서드에 따라 조건문으로 함수를 분리해서 api를 작성했다.&lt;/p&gt;
&lt;pre id=&quot;code_1664180269731&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// http통신을 하기위해 http모듈을 불러온다
const http = require('http');
// sendProducts를 가져와서 쓰기위한 코드. require('sendProducts가있는 파일경로')
const {sendProducts} = require('./sendProducts');

// http의 createServer함수로 서버를 만들어서 server변수에 담아줌
const server = http.createServer((req, res) =&amp;gt; {
    // url = req.url, method = req.method(구조분해할당)
    const {url, method} = req;
    // 응답의 형태가 json이라는 것을 알려줌
    res.setHeader('Content-Type', 'application/json');

    if (url === '/ping'){
        return res.end(JSON.stringify({message: &quot;/ pong&quot;}))
    }
    if (url === '/signup' &amp;amp;&amp;amp; method === 'POST') return res.end(JSON.stringify({message: '회원가입 완료!'}))
    if (url === '/login' &amp;amp;&amp;amp; method === 'POST') return res.end(JSON.stringify({message: '로그인 완료!'}))
    if (url === '/products' &amp;amp;&amp;amp; method === 'GET')return sendProducts(res)

    // 응답으로 보내주는 데이터
    res.end(JSON.stringify({ message: 'this response answers to every request' }));
})
// 서버를 켜는 명령어 listen 8000번 포트에서 켠다.
server.listen(8000, () =&amp;gt; (
    // 서버가 켜지면 동작
    console.log(&quot;server is running on PORT 8000&quot;)
))&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sendProducts.js&lt;/p&gt;
&lt;pre id=&quot;code_1664183938382&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const sendProducts = (res) =&amp;gt; {
  res.end(
	  JSON.stringify({ 
		  products: [{
	      id: 1,
	      productName: &quot;node&quot;,
	      description: &quot;node.js is awesome&quot;
	    }, {
	      id: 2,
	      productName: &quot;express&quot;,
	      description: &quot;express is a server-side framework for node.js&quot;
	    }]
	})
  )
}

module.exports = { sendProducts } // withoutExpress.js 에서 사용하기 위해 모듈로 내보낸다.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 서버실행(터미널)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664128436106&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node serverWithoutExpress.js&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행하면 &quot;server is running on PORT 8000&quot;이 콘솔에 찍히고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저로 localhost:8000에 접속해보면 &quot;request received&quot;가 찍힌다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;65&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cedqkx/btrM0mO8HU9/yJlaKZaxASh1xjtl6robtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cedqkx/btrM0mO8HU9/yJlaKZaxASh1xjtl6robtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cedqkx/btrM0mO8HU9/yJlaKZaxASh1xjtl6robtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcedqkx%2FbtrM0mO8HU9%2FyJlaKZaxASh1xjtl6robtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;252&quot; height=&quot;65&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;65&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;express없이 서버를 만들면 불편한점.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트의 문자열을 프론트엔드에 보내서 통신하기 위해 통신을 위한 문자열 데이터타입인 json형태로 바꿔주는 작업을 해야한다.(JSON.stringify())&lt;/li&gt;
&lt;li&gt;라우팅을 request객체에서 url과 mothod에 따라 if문으로 분기해서 처리했다.(*라우팅: 해당 자원에 대해 다른 함수(로직)을 실행하도록 하는 것) -&amp;gt; 관리가 힘들다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런걸 자동으로 해주기위해 express를 사용한다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  express로 서버 만들기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. express 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664180071123&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install express --save&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm으로 express를 설치하면 express와 express를 사용하는 데 필요한 다른 모든 패키지들을 같이 설치해준다.(node_modules폴더에서 확인)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json파일에서 내가 받은 패키지 확인 가능&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vrGsD/btrM6bU4v3y/EPskdFdYuG0mcajT5kMNKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vrGsD/btrM6bU4v3y/EPskdFdYuG0mcajT5kMNKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vrGsD/btrM6bU4v3y/EPskdFdYuG0mcajT5kMNKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvrGsD%2FbtrM6bU4v3y%2FEPskdFdYuG0mcajT5kMNKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;197&quot; height=&quot;59&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. serverWithExpress.js작성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664183860037&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express')// Express 모듈을 임포트 하고 
const app = express() // 함수를 실행해서 app 이란 변수에 담는 것이 컨벤션이다.
// 앱을 사용하는 방법 : app.method('path', handler function)
/*
1. 요청을 받을 http method로 함수를 app 에 붙인다.
2. 요청을 받을 endpoint url 을 string 으로 첫번째 인자에 넣는다.
3. 두번째 인자는 요청과 응답을 인자로 받는 콜백함수이다. 
**즉, 각각의 메소드와 엔드포인트에 대해 처리하는(핸들링) 함수가 된다.**
*/
app.get('/ping', (req, res) =&amp;gt; {
    ...
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664183225762&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// serverWithExpress.js
const http = require('http');
const express = require('express');
const {sendProducts} = require('./sendProducts2');

// express로 앱 생성
const app = express();
// 자바스크립트 객체들을 모두 json으로 변환하라고 미리 알려준다. JSON.stringify()를 쓰지 않아도 되도록.
app.use(express.json());

// express로 만든 앱에 해당 url로 get요청이 들어왔을시 이렇게 동작하겠다
// app.http메서드(url, 콜백함수)
app.get('/ping', (req, res) =&amp;gt; {
    res.json({message: '/ pong'});
});

app.post('/signup', (req, res) =&amp;gt; {res.json({message: '회원가입 완료!'})});
app.post('/login', (req, res) =&amp;gt; {res.json({message: '로그인 완료!'})});
app.get('/products', sendProducts);

// 원래는 http.createServer에 모든걸 다 넣어줬는데 위에서 분리를 다 시켜놓고 인자로 app만 준다.
const server = http.createServer(app);

server.listen(8000, () =&amp;gt; {
    console.log('server is listening on PORT 8000');
})&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sendProducts2.js&lt;/p&gt;
&lt;pre id=&quot;code_1664185522024&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const sendProducts = (req, res) =&amp;gt; {
  res.json({ // 위에서 작성한 sendProducts 함수와 비교했을 때,
  // express 덕분에 JSON.stringify 함수를 사용할 필요없이
  // response 객체의 json 메소드를 활용.
    products: [
      {
        id: 1,
        title: 'node',
        description: 'node.js is awesome',
      },
      {
        id: 2,
        title: 'express',
        description: 'express is a server-side framework for node.js',
      },
    ],
  })
}

module.exports = { sendProducts } // routing.js 에서 사용하기 위해 모듈로 내보낸다.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;express로 서버를 만드니&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건문으로 &lt;b&gt;라우팅&lt;/b&gt;을 처리했던 것이 간편해졌고&lt;/li&gt;
&lt;li&gt;각각의 요청을 처리하는 &lt;b&gt;함수의 분리&lt;/b&gt;로 인해 직관적으로 코드를 설계할 수 있게 되었다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>TIL</category>
      <category>Express</category>
      <category>node.js</category>
      <category>서버만들기</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/113</guid>
      <comments>https://ginghambagle.tistory.com/113#entry113comment</comments>
      <pubDate>Mon, 26 Sep 2022 18:51:48 +0900</pubDate>
    </item>
    <item>
      <title>웹서버(Web server)와 WAS(Web Application Server)</title>
      <link>https://ginghambagle.tistory.com/112</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;정적컨텐츠 , 동적컨텐츠&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적컨텐츠: 요청인자값에 상관없는, 변하지 않는 컨텐츠&lt;/li&gt;
&lt;li&gt;동적컨텐츠: 요청인자값에 따라 바뀔 수 있는 컨텐츠&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;285&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4QyDX/btrMYTTknU1/Z6aWLqMaHfbfBnU4j0v461/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4QyDX/btrMYTTknU1/Z6aWLqMaHfbfBnU4j0v461/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4QyDX/btrMYTTknU1/Z6aWLqMaHfbfBnU4j0v461/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4QyDX%2FbtrMYTTknU1%2FZ6aWLqMaHfbfBnU4j0v461%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;285&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;285&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✏️ 웹 서버&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저로부터 http요청을 받아서 요청에 맞는 &lt;b&gt;정적 컨텐츠&lt;/b&gt;를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;웹 서버의 기능&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트로부터 http요청을 받을수 있다.&lt;/li&gt;
&lt;li&gt;정적컨텐츠 요청시 정적 컨텐츠 제공&lt;/li&gt;
&lt;li&gt;동적컨텐츠 요청시 was로 요청전달, was가 처리한 내용을 클라이언트에 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✏️ 웹 어플리케이션 서버&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB조회나 다양한 로직처리를 요구하는 &lt;b&gt;동적인 컨텐츠&lt;/b&gt;를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;WAS의 기능&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트로부터 http요청을 받을수있다(대부분 was는 웹서버를 내장하고있기때문(웹서버+웹컨테이너))&lt;/li&gt;
&lt;li&gt;요청에맞는 정적컨텐츠를 제공할수있다&lt;/li&gt;
&lt;li&gt;db조회나 다양한 로직처리를 통해 동적컨텐츠를 제공할수있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  웹 서버가 필요한 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 어플리케이션 서버도 웹 서버의 역할을 할 수 있는데 굳이 웹 서버가 필요한 이유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버부하방지: 정적 컨텐츠는 웹 서버가 처리하고 동적 컨텐츠는 WAS가 처리하도록 해서 서버의 부하를 방지한다.&lt;/li&gt;
&lt;li&gt;로드밸런싱: Web Server를 이용해서 로드밸런싱을 하고 Web Server에서 여러 대의 WAS의 상태를 체크하고 문제가 있는 WAS를&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;사용하지 않도록 설정해둠으로서 사용자가 문제없이 이용할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;보안: WAS는 db에 접근할 수 있기 때문에 앞단에 Web Server를 둬서 외부 노출을&amp;nbsp; 차단할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web</category>
      <category>WAS</category>
      <category>웹서버</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/112</guid>
      <comments>https://ginghambagle.tistory.com/112#entry112comment</comments>
      <pubDate>Mon, 26 Sep 2022 00:38:48 +0900</pubDate>
    </item>
    <item>
      <title>GitHub 꾸미기 | waka-box : 프로필에 코딩시간 표시하기</title>
      <link>https://ginghambagle.tistory.com/111</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCWijB/btrMS4H3ClN/3pYJcjjPsaPdk3HpahXX8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCWijB/btrMS4H3ClN/3pYJcjjPsaPdk3HpahXX8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCWijB/btrMS4H3ClN/3pYJcjjPsaPdk3HpahXX8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCWijB%2FbtrMS4H3ClN%2F3pYJcjjPsaPdk3HpahXX8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;912&quot; height=&quot;366&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 메인에 위 사진처럼 언어별로 코딩시간을 표시하는법!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 사용하는 IDE와 연동해서 일주일동안 어떤 언어를 얼마나 사용해서 개발했는지 깃허브 프로필에 표시해보자~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WakaTime이라는 사이트와 깃허브 gist, waka-box레포지토리를 이용해서 설정하면 메인에 표시할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;01. GitHub 설정(Gist, token 만들기)&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp; &lt;span style=&quot;color: #666666;&quot;&gt;GitHub Gist를 만든다 -&amp;gt; &lt;a style=&quot;color: #666666;&quot; href=&quot;https://gist.github.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 &lt;b&gt;public&lt;/b&gt;으로 만들어야 한다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfFxda/btrMUTl6Wc8/zkT9L1mKmnUY7HrzW2J74K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfFxda/btrMUTl6Wc8/zkT9L1mKmnUY7HrzW2J74K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfFxda/btrMUTl6Wc8/zkT9L1mKmnUY7HrzW2J74K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfFxda%2FbtrMUTl6Wc8%2FzkT9L1mKmnUY7HrzW2J74K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1017&quot; height=&quot;633&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름은 아무렇게나 만들면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 알아서 바뀜!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  그리고 description에는 아무것도 적지 않는다. description에 waka-box로 적었더니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Weekly development breakdown이라는 제목 대신 waka-box가 떴다...수정해서 지우면 되긴 하지만 적지 않기,,,,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LGVSl/btrMS4iqizt/mkUzUB2NSDHF2L3TP3jcPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LGVSl/btrMS4iqizt/mkUzUB2NSDHF2L3TP3jcPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LGVSl/btrMS4iqizt/mkUzUB2NSDHF2L3TP3jcPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLGVSl%2FbtrMS4iqizt%2FmkUzUB2NSDHF2L3TP3jcPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;483&quot; height=&quot;212&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;span style=&quot;color: #666666;&quot;&gt;깃허브 토큰을 만든다 -&amp;gt; &lt;a style=&quot;color: #666666;&quot; href=&quot;https://github.com/settings/tokens/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;511&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eSPHTL/btrMPUM37XY/s0ZST64Y0m1USeIbwyYKvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eSPHTL/btrMPUM37XY/s0ZST64Y0m1USeIbwyYKvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eSPHTL/btrMPUM37XY/s0ZST64Y0m1USeIbwyYKvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeSPHTL%2FbtrMPUM37XY%2Fs0ZST64Y0m1USeIbwyYKvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1059&quot; height=&quot;511&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;511&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gist에 체크를 하고 만든다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만든 후 토큰값은 한번만 보여주고 다신 안보여주기 때문에(까먹으면 재발급 해야함) 복사해서 잘 저장해두기&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;02. WakaTime 계정 설정&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span style=&quot;color: #666666;&quot;&gt; WakaTime 계정을 만든다 -&amp;gt;&amp;nbsp;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://wakatime.com/signup&quot;&gt;링크&lt;/a&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PU40j/btrMRFInNwf/DKXc0l7MqINhxkJlrNwyKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PU40j/btrMRFInNwf/DKXc0l7MqINhxkJlrNwyKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PU40j/btrMRFInNwf/DKXc0l7MqINhxkJlrNwyKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPU40j%2FbtrMRFInNwf%2FDKXc0l7MqINhxkJlrNwyKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;593&quot; height=&quot;589&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브랑 연동시켜주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가입후 날아오는 이메일 인증도 완료한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;WakaTime 프로필 세팅 -&amp;gt;&amp;nbsp;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://wakatime.com/settings/profile&quot;&gt;링크&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt2a6n/btrMUS8y9u0/fy9xVwixVFDYiKvNWYAs81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt2a6n/btrMUS8y9u0/fy9xVwixVFDYiKvNWYAs81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt2a6n/btrMUS8y9u0/fy9xVwixVFDYiKvNWYAs81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt2a6n%2FbtrMUS8y9u0%2Ffy9xVwixVFDYiKvNWYAs81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;580&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Location을 선택하고 체크박스 아래 두개를 선택하고 저장&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;WakaTime Api Key 복사 -&amp;gt;&amp;nbsp;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://wakatime.com/settings/api-key&quot;&gt;링크&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키를 복사해서 저장해둔다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;VSCode랑 연동&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;내가 사용하는 VSCode기준!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;extensions에서 wakatime 검색해서 설치한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1155&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg1aWs/btrMPPMcDUA/oLzWmvk4uGn5QpUV6TlTzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg1aWs/btrMPPMcDUA/oLzWmvk4uGn5QpUV6TlTzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg1aWs/btrMPPMcDUA/oLzWmvk4uGn5QpUV6TlTzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg1aWs%2FbtrMPPMcDUA%2FoLzWmvk4uGn5QpUV6TlTzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1155&quot; height=&quot;242&quot; data-origin-width=&quot;1155&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;command + shift + p 를 눌러서 WkaTime: API Key 검색 후 wakatime api key 입력&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MKDAo/btrMTfCCFAQ/I5IMpkiYbAG2OsGT5eEcU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MKDAo/btrMTfCCFAQ/I5IMpkiYbAG2OsGT5eEcU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MKDAo/btrMTfCCFAQ/I5IMpkiYbAG2OsGT5eEcU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMKDAo%2FbtrMTfCCFAQ%2FI5IMpkiYbAG2OsGT5eEcU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;59&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkDji4/btrMRGgMiQu/ZiYMebXm6QcsJUDTCY8wl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkDji4/btrMRGgMiQu/ZiYMebXm6QcsJUDTCY8wl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkDji4/btrMRGgMiQu/ZiYMebXm6QcsJUDTCY8wl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkDji4%2FbtrMRGgMiQu%2FZiYMebXm6QcsJUDTCY8wl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;456&quot; height=&quot;56&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;03. waka-box Repo 설정&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;waka-box Repo Fork&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/matchai/waka-box&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waka-box 레포지토리&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1663911708348&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - matchai/waka-box:   Update a pinned gist to contain your weekly WakaTime stats&quot; data-og-description=&quot;  Update a pinned gist to contain your weekly WakaTime stats - GitHub - matchai/waka-box:   Update a pinned gist to contain your weekly WakaTime stats&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/matchai/waka-box&quot; data-og-url=&quot;https://github.com/matchai/waka-box&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/buw4eN/hyPT7Nz94D/azKsLU6k4uraAvZ8Lxw73k/img.png?width=1200&amp;amp;height=600&amp;amp;face=1020_161_1061_206&quot;&gt;&lt;a href=&quot;https://github.com/matchai/waka-box&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/matchai/waka-box&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/buw4eN/hyPT7Nz94D/azKsLU6k4uraAvZ8Lxw73k/img.png?width=1200&amp;amp;height=600&amp;amp;face=1020_161_1061_206');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - matchai/waka-box:   Update a pinned gist to contain your weekly WakaTime stats&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Update a pinned gist to contain your weekly WakaTime stats - GitHub - matchai/waka-box:   Update a pinned gist to contain your weekly WakaTime stats&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 레포지토리를 fork해서 가져온다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span style=&quot;color: #666666;&quot;&gt; Secret설정하기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fork해온 레포지토리에서 Settings-&amp;gt;Secrets-&amp;gt;Actions로 가서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;New repository secret을 설정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1411&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drzT21/btrMS3hP3wt/YL47GJtHU8BIZHdMycmNU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drzT21/btrMS3hP3wt/YL47GJtHU8BIZHdMycmNU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drzT21/btrMS3hP3wt/YL47GJtHU8BIZHdMycmNU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrzT21%2FbtrMS3hP3wt%2FYL47GJtHU8BIZHdMycmNU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1411&quot; height=&quot;822&quot; data-origin-width=&quot;1411&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Name : Secret&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GH_TOKEN : 아까 발급받은 깃허브 토큰&lt;/li&gt;
&lt;li&gt;GIST_ID : 아까 생성한 gist 주소에서 뒷부분 https://gist.github.com/깃헙아이디/a79bc4e058ed913b418cafeffccd2fd9&lt;/li&gt;
&lt;li&gt;WAKATIME_API_KEY : 아까 복사한 WakaTime Api Key&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ltFpt/btrMSMAP8bd/rkK9PzbJO1KxPrFBWG3n40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ltFpt/btrMSMAP8bd/rkK9PzbJO1KxPrFBWG3n40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ltFpt/btrMSMAP8bd/rkK9PzbJO1KxPrFBWG3n40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FltFpt%2FbtrMSMAP8bd%2FrkK9PzbJO1KxPrFBWG3n40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;990&quot; height=&quot;341&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 세가지를 설정한다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span style=&quot;color: #666666;&quot;&gt; schedule.yml 코드 변경&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fork해온 repository에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.github/workflows/schedule.yml 을 열어서 GIST_ID 부분을 아래처럼 수정한다.&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOTOyb/btrMTlWSSKH/K0BNZ2j5DybDItMSIseGwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOTOyb/btrMTlWSSKH/K0BNZ2j5DybDItMSIseGwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOTOyb/btrMTlWSSKH/K0BNZ2j5DybDItMSIseGwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOTOyb%2FbtrMTlWSSKH%2FK0BNZ2j5DybDItMSIseGwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;676&quot; height=&quot;503&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✔️&amp;nbsp;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;enable workflow&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;레포지토리의 Action탭에서 workflow를 활성화한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WilXl/btrMSWQlL8X/uB8aZRcf6Sz1XPTE7ZJUAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WilXl/btrMSWQlL8X/uB8aZRcf6Sz1XPTE7ZJUAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WilXl/btrMSWQlL8X/uB8aZRcf6Sz1XPTE7ZJUAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWilXl%2FbtrMSWQlL8X%2FuB8aZRcf6Sz1XPTE7ZJUAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1366&quot; height=&quot;600&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0PJv7/btrMTeiTvsv/2xGGsbbWy0JEqzpRfg0wH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0PJv7/btrMTeiTvsv/2xGGsbbWy0JEqzpRfg0wH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0PJv7/btrMTeiTvsv/2xGGsbbWy0JEqzpRfg0wH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0PJv7%2FbtrMTeiTvsv%2F2xGGsbbWy0JEqzpRfg0wH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1426&quot; height=&quot;472&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;마지막. 메인에 pin하기&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;191&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w6DTr/btrMTkFjT1X/SL3FEI9cEcX3iI3WEkWnXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w6DTr/btrMTkFjT1X/SL3FEI9cEcX3iI3WEkWnXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w6DTr/btrMTkFjT1X/SL3FEI9cEcX3iI3WEkWnXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw6DTr%2FbtrMTkFjT1X%2FSL3FEI9cEcX3iI3WEkWnXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;427&quot; height=&quot;191&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;191&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이렇게 제대로 뜨지 않으면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레포지토리 -&amp;gt; Actions -&amp;gt; Update gist with WakaTime stats로 들어가서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽의 run workflow -&amp;gt; run workflow를 눌러준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DJh6e/btrMUFPdQoy/m3yybT1pNFG4NLxxcaIxB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DJh6e/btrMUFPdQoy/m3yybT1pNFG4NLxxcaIxB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DJh6e/btrMUFPdQoy/m3yybT1pNFG4NLxxcaIxB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDJh6e%2FbtrMUFPdQoy%2Fm3yybT1pNFG4NLxxcaIxB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;235&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✨ 완료&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqVy1R/btrMUNGhDB5/HLEbKysyri4HrgSgf4cgmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqVy1R/btrMUNGhDB5/HLEbKysyri4HrgSgf4cgmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqVy1R/btrMUNGhDB5/HLEbKysyri4HrgSgf4cgmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqVy1R%2FbtrMUNGhDB5%2FHLEbKysyri4HrgSgf4cgmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;481&quot; height=&quot;209&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;209&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>기타</category>
      <category>waka-box</category>
      <category>Weekly development breakdown</category>
      <category>깃허브</category>
      <category>꾸미기</category>
      <category>코딩시간</category>
      <author>이라후</author>
      <guid isPermaLink="true">https://ginghambagle.tistory.com/111</guid>
      <comments>https://ginghambagle.tistory.com/111#entry111comment</comments>
      <pubDate>Sun, 25 Sep 2022 14:13:49 +0900</pubDate>
    </item>
  </channel>
</rss>