<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코딩일기</title>
    <link>https://daily-coding-diary.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 11:56:42 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>hyun_ji</managingEditor>
    <image>
      <title>코딩일기</title>
      <url>https://tistory1.daumcdn.net/tistory/4821082/attach/7bc849fc2f014427827ccca5148e5291</url>
      <link>https://daily-coding-diary.tistory.com</link>
    </image>
    <item>
      <title>버퍼 변환 사이트 buffer converter</title>
      <link>https://daily-coding-diary.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;서버 작업할 때, 테스트용으로 사용하면 편리한 버퍼 변환기입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구글에 치면 버퍼 변환기가 나오기는 하나 이미지 확장자만 지원하는 경우가 많고&lt;/li&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;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; href=&quot;https://fkwsur.github.io/buffer_converter/&quot;&gt;fkwsur.github.io/buffer_converter/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1699388815125&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;fkwsur.github.io&quot; data-og-source-url=&quot;https://fkwsur.github.io/buffer_converter/&quot; data-og-url=&quot;https://fkwsur.github.io/buffer_converter/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://fkwsur.github.io/buffer_converter/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://fkwsur.github.io/buffer_converter/&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;내가 편하려고 만든 파일 버퍼 변환기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;fkwsur.github.io&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;</description>
      <category>기타</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/70</guid>
      <comments>https://daily-coding-diary.tistory.com/70#entry70comment</comments>
      <pubDate>Wed, 8 Nov 2023 05:31:44 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 외래키 쓰면 안되는 이유</title>
      <link>https://daily-coding-diary.tistory.com/67</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;외래키(Foreign Key)&lt;/b&gt;는 데이터베이스에서 두 테이블 간의 관계를 정의할 때 사용하는 개념 외래키는 한 테이블의 필드(또는 컬럼)가 다른 테이블의 기본 키(Primary Key)를 참조할 때 사용 이렇게 하는 것으로 &lt;b&gt;데이터의 일관성과 무결성&lt;/b&gt;이 보장되지만, 몇 가지 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;단점&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 data-ke-size=&quot;size16&quot;&gt;1. 성능 문제 외래키를 사용하면 INSERT, UPDATE, DELETE 작업 시 해당 테이블뿐만 아니라 &lt;span style=&quot;color: #ee2323;&quot;&gt;참조하는 테이블까지 확인&lt;/span&gt;해야 함. 이로 인해 &lt;span style=&quot;color: #ee2323;&quot;&gt;작업 속도가 느려질&lt;/span&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;2. &lt;span style=&quot;color: #ee2323;&quot;&gt;복잡성 증가&lt;/span&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;3. 삭제 제한 외래키로 참조되는 테이블의 데이터를 삭제하려고 할 때, 그 데이터를 참조하는 다른 테이블의 데이터가 존재하면 &lt;span style=&quot;color: #ee2323;&quot;&gt;삭제가 불가&lt;/span&gt;능함. 이를 '캐스캐이드 삭제' 옵션으로 해결할 수 있지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 설정으로 데이터 손실의 위험&lt;/span&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;4. 데이터 추가 제한 참조하는 테이블에 없는 값을 외래키 컬럼에 입력하려고 하면 오류가 발생함. 이는 데이터의 무결성을 위한 것이지만, 때로는 &lt;span style=&quot;color: #ee2323;&quot;&gt;데이터 입력이 제한&lt;/span&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. &lt;span style=&quot;color: #ee2323;&quot;&gt;데이터 이관의 어려움&lt;/span&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;6. &lt;span style=&quot;color: #ee2323;&quot;&gt;변경의 어려움&lt;/span&gt; 나중에 데이터베이스 구조를 변경하거나 수정할 때, 외래키 때문에 간접적으로 많은 테이블들에 영향을 줄 수 있음.&lt;/p&gt;</description>
      <category>Database/mysql</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/67</guid>
      <comments>https://daily-coding-diary.tistory.com/67#entry67comment</comments>
      <pubDate>Mon, 28 Aug 2023 18:15:06 +0900</pubDate>
    </item>
    <item>
      <title>[Node.js] iamport 결제 실패 시의 상황 대처법</title>
      <link>https://daily-coding-diary.tistory.com/60</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;결제시스템은 결제를 한다고 다가 아닙니다.&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;그러므로 안전하게 이를 핸들링하기 위해 상태값 중 결제 대기 상태를 만듭니다.&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;우선 결제 대기 로직입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691675482437&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// 결재 대기 로직
	WaitAccept :  async (req, res) =&amp;gt; {
		try {
			let {payment, user_id} = req.body;
			const rows = await pay_report.create({
				user_id : user_id,
				pay_method : payment.pay_method,
				merchant_uid : payment.merchant_uid,
				paid_amount : payment.amount,
				buyer_name : payment.buyer_name,
				buyer_email : payment.buyer_email,
				buyer_tel : payment.buyer_tel,
				buyer_addr : payment.buyer_addr,
				buyer_postcode : payment.buyer_postcode,
				card_name : payment.card_name,
				bank_name : payment.bank_name,
				card_quota : payment.card_quota,
				card_number : payment.card_number,
				is_complete : 1
			})
  			if(rows) return res.code(200).send({result : true});
			else throw &quot;에러&quot;;
		} catch (error) {
			return res.code(200).send({error : error});
		}
	},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 결제가 정상적으로 완료되면 아래의 예시 코드가 되겠죠&lt;/p&gt;
&lt;pre id=&quot;code_1691675510268&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// 결재 로직
	Accept :  async (req, res) =&amp;gt; {
		try {
			let {payment, user_id} = req.body;
			const getToken = await axios.post('https://api.iamport.kr/users/getToken', {
				imp_key : process.env.imp_key,
				imp_secret : process.env.imp_secret
			})
			// 실제로 결제내역이 있는지 아이엠포트 서버에서 확인
			const retval = await axios.post(util.format('https://api.iamport.kr/payments/%s',payment.imp_uid),{
			}, {
				headers: {
					Authorization: getToken.data.response.access_token,
				}
			});
			// 아이엠포트 서버에 결제내역이 없을 경우
			if (retval.data.response.status != &quot;paid&quot;) {
				throw &quot;에러&quot;;
            }
			// 아이엠포트 서버상의 가격과 유저의 요청 가격 맞는지 비교
			if(retval.data.response.amount != payment.paid_amount){
				throw &quot;에러&quot;;
            }
			// 이전 결재대기 로직 불러와서 결재완료 시키기
			const rows = await pay_report.update({
				is_complete :  0,
				imp_uid : payment.imp_uid
			  },{
				where :{user_id : user_id, merchant_uid : payment.merchant_uid}
			  })
			  console.log(rows)
  			if(rows) return res.code(200).send({result : true});
			else throw &quot;에러&quot;;
		} catch (error) {
			return res.code(200).send({error : error});
		}
	},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결제 취소 신청은 이렇게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691675707867&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	Cancel :  async (req, res) =&amp;gt; {
		try {
			let {merchant_uid, reason} = req.body;
			const rows = await pay_report.findOne({
				where : {merchant_uid : merchant_uid}
			})
			if (!rows) throw  &quot;에러&quot;;
			const getToken = await axios.post('https://api.iamport.kr/users/getToken', {
				imp_key : process.env.imp_key,
				imp_secret : process.env.imp_secret
			})
			const getCancelData = await axios.post('https://api.iamport.kr/payments/cancel', {
				reason : reason, // 가맹점 클라이언트로부터 받은 환불사유
				imp_uid : rows.imp_uid, // imp_uid를 환불 `unique key`로 입력
				amount: rows.paid_amount, // 가맹점 클라이언트로부터 받은 환불금액
				checksum: rows.paid_amount // [권장] 환불 가능 금액 입력
            },
			{
				headers: {
					Authorization: getToken.data.response.access_token,
				},
			})
			if(getCancelData.data.code == 0){
				// 업데이트 실패 시, 기록 따로 저장하는 로직 필요
				await pay_report.update({
					is_complete: 2,
					cancel_reason : reason
				}, {
					where : { merchant_uid : merchant_uid}
				})
				return res.code(200).send({result : true});
			}else{
				return res.code(200).send({result : false});
			}
		} catch (error) {
			return res.code(200).send({error : error});
		}
	},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결제 기록 가져오기입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691675923760&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	GetPayment :  async (req, res) =&amp;gt; {
		try {
			let {user_id} = req.query;
			const rows = await pay_report.findAll({
				where : {user_id : user_id,is_complete : 0},
				order: [[&quot;createdAt&quot;, &quot;desc&quot;]]
			})
			if (!rows) throw &quot;에러&quot;;
			return  res.code(200).send(rows);
		} catch (error) {
			return res.code(200).send({error : error});
		}
	},&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;이럴땐 아이엠포트 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;방법은 두가지 인데요.&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;두번째는 프론트에서 서버로의 요청이 실패하면 사이드 서버로 결제 내역을 보내준 뒤, 사이드 서버에서 카프카에 그 내용을 저장합니다. 그리고 카프카에 있는 데이터를 지속적으로 소비하면서 본서버에 결제완료 api 요청을 보내고 요청이 실패할 시, 다시 카프카에 담는 방법입니다.&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;(모듈이나 자세한 세팅방법은 생략했습니다. 자세한 내용은 본문 하단에 링크된 깃에서 확인해주세요)&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;nbsp;코드&amp;nbsp;예시입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691677290798&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const getInfo = async () =&amp;gt; {

    const getToken = await axios.post('https://api.iamport.kr/users/getToken', {
				imp_key : process.env.imp_key,
				imp_secret : process.env.imp_secret
			})

    const rows = await pay_report.findAll({
        where : {is_complete : 1},
    })

    for(const element of rows){
        const retval = await axios.post(util.format('https://api.iamport.kr/payments/find/%s/paid',element.merchant_uid),{
        }, {
            headers: {
                Authorization: getToken.data.response.access_token,
            }
        });
        
        if (retval.data.response.status == &quot;paid&quot; &amp;amp;&amp;amp; retval.data.response.amount == element.paid_amount) {
            await pay_report.update({
                is_complete :  0,
                imp_uid : retval.data.response.imp_uid
              },{
                where :{user_id : element.user_id, merchant_uid : element.merchant_uid}
            })
        }else{
            console.log(&quot;해당 없음&quot;)
        }
    };
}

getInfo();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이드 서버 예시입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691677319204&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.post('/api/v1/payment/sendside', async (req, res) =&amp;gt; {
    try {
        let {payment, user_id} = req.body;
        // user_id 토큰 해쉬하는 로직 있어야 함
        const data = JSON.stringify(payment)
        await producer.send({
          topic: &quot;iamport_kafka&quot;,
          messages: [
              {
              value : Buffer.from({&quot;data&quot;:data,&quot;user_id&quot;:user_id}),
          }],
        });
        return res.code(200).send({result : &quot;success&quot;});
    } catch (error) {
        return res.code(200).send({error : &quot;error&quot;});
    }
})


const consumerRun = async () =&amp;gt; {
    await consumer.connect();
    await consumer.subscribe({ topic: &quot;iamport_kafka&quot;, fromBeginning: true });
    await consumer.run({
        eachMessage: async({topic, partition, message}) =&amp;gt; {
            let data = await JSON.parse(message.value.toString())
                try {
                // 본 서버로 카프카 데이터 꺼내서 요청
                await axios.post('http://localhost:8081/api/v1/payment/accept', {
                    payment : data.data,
                    user_id : data.user_id
                })
                } catch (err) {
                // 통신 실패하면 다시 카프카에 담기
                await producer.send({
                    topic: &quot;iamport_kafka&quot;,
                    messages: [
                        {
                        value : message.value
                    }],
                });
                }
        }
    })
}

app.listen({ port: 8082 }, (err) =&amp;gt; { if (err) throw err }, () =&amp;gt; {
console.log(&quot;running on port 8082&quot;);
});


kafkaConnect();
consumerRun().catch(err =&amp;gt; console.log(&quot;kafka err : &quot;, err))&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;blockquote data-ke-style=&quot;style3&quot;&gt;프론트에서 바로 카프카에 안담고 왜 서버로 보내는가?&lt;br /&gt;- 카프카에 JWT같은 인증시스템이 없으니까 보안이 안좋다. 프론트에서 바로 MYSQL접근 안하게 하는거랑 같은 원리이므로 서버로 보내줘야 하는 함&lt;br /&gt;&lt;br /&gt;왜 사이드 서버에서 바로 디비에 업데이트하면 안되고 다시 본 서버로 api 요청 날려서 데이터 내용 수정해야하는가?&lt;br /&gt;- 일반적으로 디비에 대한 정보를 많은 프로젝트가 가지고 있는건 보안에 안좋다. 싱크서버같이 어쩔수없는 경우가 있겠지만, 저런건 굳이 없어도 되니 차라리 API요청을 하는게 좋다.&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;감사합니다.&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://github.com/fkwsur/Node_Iamport_Payment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/fkwsur/Node_Iamport_Payment&lt;/a&gt;&lt;/p&gt;</description>
      <category>Node.js</category>
      <category>fasify</category>
      <category>iamport</category>
      <category>node</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/60</guid>
      <comments>https://daily-coding-diary.tistory.com/60#entry60comment</comments>
      <pubDate>Thu, 10 Aug 2023 23:53:02 +0900</pubDate>
    </item>
    <item>
      <title>[Elasticsearch] 03. db연동하기</title>
      <link>https://daily-coding-diary.tistory.com/58</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;전차수들에서 엘라스틱 서치를 세팅하고 노리 형태소 분석기도 적용했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이제 데이터베이스에 있는 값을 엘라스틱 서치와 연동해서 검색해 봅시다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;일반적으로 엘라스틱 서치는 로그스태시를 사용하여 디비와 연동을 하지만, 버전을 맞춰줘야 하고 설정파일도 만져줘야 하는 등 까다롭고 m1에서 호환이 잘되지 않는 단점이 있습니다.&lt;/span&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;결국엔 로그스태시도 계속 켜놓은 상태로 일정 시간 주기로 스케줄링을 해주는 원리로 돌아가기에 배치서버 만들어서 돌리는 것과 성능에는 별 차이가 없기도 하고, 직접핸들링 하는 게 저는 더 편하기 때문에 로그스태시 같은&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;배치서버를 직접 만들겠습니다.&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;1. 서버 세팅&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;node 서버에 express 프레임워크 세팅해서 진행하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;서버세팅법과 crud 부분은 아래의 링크를 참고해 주세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #6164c6;&quot;&gt;&lt;a style=&quot;color: #6164c6;&quot; href=&quot;https://daily-coding-diary.tistory.com/2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://daily-coding-diary.tistory.com/2&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690280242655&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;[Node.js] 01. 시작하기(express)&quot; data-og-description=&quot;Node.js와 React를 이용하여 나만의 Todolist를 만들어봅시다. Todolist를 이용하면 기본적인 데이터 처리 기능 CRUD(create, read, update, delete)를 구현할 수 있으므로 모든 API 시작과 끝을 맛볼 수 있게 됩니&quot; data-og-host=&quot;daily-coding-diary.tistory.com&quot; data-og-source-url=&quot;https://daily-coding-diary.tistory.com/2&quot; data-og-url=&quot;https://daily-coding-diary.tistory.com/2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dgQ2H6/hyTqriDOCA/aoXafCLWK4jv5LBKOrNlNK/img.png?width=800&amp;amp;height=489&amp;amp;face=0_0_800_489,https://scrap.kakaocdn.net/dn/bGMsr5/hyTqyaZ8my/oCUNVLGCucqOiE45R4kTN1/img.png?width=800&amp;amp;height=489&amp;amp;face=0_0_800_489,https://scrap.kakaocdn.net/dn/baQl6o/hyTqCLek7r/adkKr3cahqnGDuGP36fXGK/img.png?width=840&amp;amp;height=539&amp;amp;face=0_0_840_539&quot;&gt;&lt;a href=&quot;https://daily-coding-diary.tistory.com/2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daily-coding-diary.tistory.com/2&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dgQ2H6/hyTqriDOCA/aoXafCLWK4jv5LBKOrNlNK/img.png?width=800&amp;amp;height=489&amp;amp;face=0_0_800_489,https://scrap.kakaocdn.net/dn/bGMsr5/hyTqyaZ8my/oCUNVLGCucqOiE45R4kTN1/img.png?width=800&amp;amp;height=489&amp;amp;face=0_0_800_489,https://scrap.kakaocdn.net/dn/baQl6o/hyTqCLek7r/adkKr3cahqnGDuGP36fXGK/img.png?width=840&amp;amp;height=539&amp;amp;face=0_0_840_539');&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;[Node.js] 01. 시작하기(express)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Node.js와 React를 이용하여 나만의 Todolist를 만들어봅시다. Todolist를 이용하면 기본적인 데이터 처리 기능 CRUD(create, read, update, delete)를 구현할 수 있으므로 모든 API 시작과 끝을 맛볼 수 있게 됩니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daily-coding-diary.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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;2. 디비 세팅&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;mysql에 foods 테이블을 생성하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; text-align: start;&quot;&gt;sync 컬럼은 엘라스틱 서치 인덱스와 연동 완료된 경우에는 0, 새롭게 생성해야 하거나 업데이트해야 할 것은 1, 삭제해야 할 데이터의 값을&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;-1로 저장하겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000; text-align: start;&quot;&gt;간단한 crud로 테이블에 음식들을 아래와 같이 세팅했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000; text-align: start;&quot;&gt;나중에 조회가 많이 일어나는 경우 인덱싱 설정을 해주면 성능면에서 좋겠죠.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-27 오전 12.06.17.png&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7LcFN/btso6iQcKlw/ERGWYulcltKJoGsGrqM3Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7LcFN/btso6iQcKlw/ERGWYulcltKJoGsGrqM3Qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7LcFN/btso6iQcKlw/ERGWYulcltKJoGsGrqM3Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7LcFN%2Fbtso6iQcKlw%2FERGWYulcltKJoGsGrqM3Qk%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;762&quot; height=&quot;533&quot; data-filename=&quot;스크린샷 2023-07-27 오전 12.06.17.png&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;533&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이제 &quot;파스타파스타 2&quot;라고 검색하면 &quot;파스타&quot; 키워드가 들어간 값이 나오게, &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;또는 &quot;크림 파스타&quot;가 아닌 &quot;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;파스타크림&quot; 등 키워드가 정확하게 일치하지 않아도 &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000; text-align: start;&quot;&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-filename=&quot;스크린샷 2023-07-25 오후 7.24.22.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpPy6b/btso1vHOhg1/75spykddEMtN6mwAqq7tdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpPy6b/btso1vHOhg1/75spykddEMtN6mwAqq7tdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpPy6b/btso1vHOhg1/75spykddEMtN6mwAqq7tdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpPy6b%2Fbtso1vHOhg1%2F75spykddEMtN6mwAqq7tdK%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;768&quot; data-filename=&quot;스크린샷 2023-07-25 오후 7.24.22.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;768&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;span style=&quot;color: #000000; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000; text-align: start;&quot;&gt;sync 컬럼 변경사항 반영&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;우선 api 서버에서 crud가 일어나면 &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000; text-align: start;&quot;&gt;&amp;nbsp;create,update일 경우에는 sync를 1, delete 일 때는 -1로 값을 업데이트해 주면 되겠죠.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690281531264&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.post('/add', async (req,res) =&amp;gt; {
  try {
    let {name} = req.body;
      const rows  = await db.foods.create({
        name : name,
        sync : 1
      })
      if(!rows) throw &quot;에러&quot;;
      return res.status(200).json({&quot;result&quot; : &quot;success&quot;})
  } catch (error) {
    console.log(error)
    res.status(200).json({&quot;error&quot; : &quot;에러&quot;})
  }
})&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;4. 배치 서버 작업&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;이제 배치서버를 생성하여, 일정시간마다(개발 환경에 맞게 유동적으로 조절) 테이블에서 데이터를 조회하여 상태가 1이면 엘라스틱 서치 인덱스에 값을 생성하거나 업데이트시켜 주고,&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;-1이면 인덱스에 있는 값을 삭제하겠습니다.&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;값을 생성하거나 업데이트하는 경우에는 (이미 인덱스에 있는 id값을 기준으로 새로운 값을 넣으면 값이 업데이트가 되기 때문에 업데이트하는 경우에도 생성할 때와 똑같은 방식으로 넣어주면 됩니다.) 인덱스의 정보와 들어갈 값을 넣어주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;값을 삭제하는 경우에는 삭제할 인덱스의 정보만 넣어주면 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;for문이 돌때마다 값을 넣거나 지우는 것은 비효율적이니 엘라스틱 서치에서 지원하는 bulk로 처리했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;마지막으로 엘라스틱 서치와 연동하는 작업을 마쳤다면 생성, 수정의 경우에는 sync 컬럼의 값이 0이 되고, 삭제의 경우에는 디비에 있는 데이터를 삭제되게 해주면 &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;간단한 배치서버 만들기는 완료입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690297224903&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 엘라스틱 서치와 상관없는 다른 모듈 생략
const { Client } = require('@elastic/elasticsearch');
const client = new Client({
  // cloud: { id: '&amp;lt;cloud-id&amp;gt;' },
  // auth: { apiKey: 'base64EncodedKey' }
  node : &quot;http://localhost:9200&quot;
})

const Batch = async () =&amp;gt; {
    try {
      let query =  'select * from foods where sync in(?,?)'
      const rows = await sequelize.query(query, {
        replacements: [&quot;1&quot;,&quot;-1&quot;],
        type: QueryTypes.SELECT,
      });
      let update_data = [];
      let del_data = [];
      let dataset =[];
      for(element of rows){
        if(element.sync == '1'){
          dataset.push({index: {_index: &quot;reallasttest&quot;,_type: &quot;_doc&quot;, _id: element.idx}},{name: element.name});
          update_data.push(element.idx);
        }else if(element.sync == '-1'){
          dataset.push({delete:{_index:&quot;reallasttest&quot;, _id: element.idx}});
          del_data.push(element.idx);
        }
      }

      if(dataset.length == 0) return
      
      await client.bulk({
        body: dataset
      })

      await db.foods.update({
        sync : &quot;0&quot;
      },{
        where : { idx : update_data }
      })
      
      await db.foods.destroy({ where: { idx: del_data }})

    } catch (error) {
      console.log(error);
    }
}
  
setInterval(() =&amp;gt; {
   Batch();
}, 2000);&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위의 예시에서는 &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; text-align: start;&quot;&gt;@elastic/elasticsearch&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; (&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;a style=&quot;color: #0593d3;&quot; href=&quot;https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자바스크립트에서 엘라스틱서치를 사용할 수 있는 모듈&lt;/a&gt;&lt;/span&gt;)을 사용했으나,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직접 axios로 &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;a style=&quot;color: #0593d3;&quot; href=&quot;https://esbook.kimjmin.net/04-data/4.2-crud&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http 통신&lt;/a&gt;&lt;/span&gt; 구현하여 바로 요청을 날리셔도 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 방식이 다른 언어까지 고려하면 통일성은 좋긴 하지만 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다른 언어들도 각자 모듈로 지원해 주기 때문에 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본인 취향대로 작성하시면 됩니다.&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;5. 결과 확인&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이제 다시 api 서버에 돌아와서 유저가 입력한 키워드를 가지고 엘라스틱 서치 인덱스를 조회해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690298821688&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.get('/search', async (req,res) =&amp;gt; {
  try {
      let {keyword} = req.query;
      // 검색 전 최신값으로 새로고침
      await client.indices.refresh({ index: 'reallasttest' })
      // 검색
      const result = await client.search({
        index: 'reallasttest',
        query: {
          match: { name: keyword }
        }
      })
    return res.status(200).json(result.hits.hits)
  } catch (error) {
    console.log(error);
    res.status(200).json({&quot;error&quot; : &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-filename=&quot;스크린샷 2023-07-26 오전 12.27.48.png&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;818&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7SjRR/btso23xIvij/gvIiyk3idBAIhoPCEFWqD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7SjRR/btso23xIvij/gvIiyk3idBAIhoPCEFWqD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7SjRR/btso23xIvij/gvIiyk3idBAIhoPCEFWqD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7SjRR%2Fbtso23xIvij%2FgvIiyk3idBAIhoPCEFWqD1%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;839&quot; height=&quot;818&quot; data-filename=&quot;스크린샷 2023-07-26 오전 12.27.48.png&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;818&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;처음 목표로 했던 대로 결과가 나오네요. &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;(참고로 엘라스틱 서치 서버는 포트가 9200입니다. 엘라스틱 서치에서 제공하는 요청이 아닌 직접 작성한 서버로 요청을 보낸 것이니 헷갈리지 마시길..)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이렇게 나오면 성공입니다.^^ (&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;간단하게 엘라스틱 서치를 익히기 위한 용도로 만든 프로젝트니 자세한 설정이나 옵션은 본인 개발 환경에 맞게 작성하시면 됩니다.)&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;자세한 코드는 제 깃에서 확인해 주세요 &amp;darr;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #6164c6;&quot;&gt;&lt;a style=&quot;color: #6164c6;&quot; href=&quot;https://github.com/fkwsur/Basic_Node_Elasticsearch_With_Nori&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/fkwsur/Basic_Node_Elasticsearch_With_Nori&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Elasticsearch</category>
      <category>db</category>
      <category>Elasticsearch</category>
      <category>Logstash</category>
      <category>mysql</category>
      <category>node</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/58</guid>
      <comments>https://daily-coding-diary.tistory.com/58#entry58comment</comments>
      <pubDate>Wed, 26 Jul 2023 00:44:24 +0900</pubDate>
    </item>
    <item>
      <title>[Elasticsearch] 02. Elasticsearch 사용하기 (with nori)</title>
      <link>https://daily-coding-diary.tistory.com/57</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ElasticSearch 를 사용해보겠습니다.&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;&lt;span style=&quot;color: #000000;&quot;&gt;1. 엘라스틱 서치 설치 및 실행&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 엘라스틱 서치를 설치해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;저는 m1 이라 brew 로 설치했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690191791737&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ brew tap elastic/tap
$ brew install elasticsearch-full
$ brew services start elastic/tap/elasticsearch-full&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;http://localhost:9200 브라우저로 들어가보면&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690191860312&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot; : &quot;&quot;,
  &quot;cluster_name&quot; : &quot;&quot;,
  &quot;cluster_uuid&quot; : &quot;&quot;,
  &quot;version&quot; : {
    &quot;number&quot; : &quot;7.17.4&quot;,
    &quot;build_flavor&quot; : &quot;default&quot;,
    &quot;build_type&quot; : &quot;tar&quot;,
    &quot;build_hash&quot; : &quot;79878662c54c886ae89206c685d9f1051a9d6411&quot;,
    &quot;build_date&quot; : &quot;2022-05-18T18:04:20.964345128Z&quot;,
    &quot;build_snapshot&quot; : false,
    &quot;lucene_version&quot; : &quot;8.11.1&quot;,
    &quot;minimum_wire_compatibility_version&quot; : &quot;6.8.0&quot;,
    &quot;minimum_index_compatibility_version&quot; : &quot;6.0.0-beta1&quot;
  },
  &quot;tagline&quot; : &quot;You Know, for Search&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 내용이 나오면 성공입니다.&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;키바나도 설치합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;키바나는 엘라스틱서치의 데이터를 시각화한 대시보드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690191946734&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ brew tap elastic/tap
$ brew install kibana-full
$ brew services start elastic/tap/kibana-full&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;http://localhost:5601 로 접속했을 시,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-24 오후 6.47.27.png&quot; data-origin-width=&quot;1899&quot; data-origin-height=&quot;819&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzcGdW/btsoRCASqmy/LiMxf7Vs1YKNEdmT81XakK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzcGdW/btsoRCASqmy/LiMxf7Vs1YKNEdmT81XakK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzcGdW/btsoRCASqmy/LiMxf7Vs1YKNEdmT81XakK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzcGdW%2FbtsoRCASqmy%2FLiMxf7Vs1YKNEdmT81XakK%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;1899&quot; height=&quot;819&quot; data-filename=&quot;스크린샷 2023-07-24 오후 6.47.27.png&quot; data-origin-width=&quot;1899&quot; data-origin-height=&quot;819&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 화면이 나오면 성공입니다.&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;3. 노리형태소 분석기 설치 및 연동&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 노리형태소 분석기를 붙일 겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;영어 기준으로 엘라스틱 서치를 이용하면 형태소가 분리되어 검색이 원활이 되지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;한글로 이용하면 형태소 분석이 지원되지 않는 이슈가 있어 노리 형태소 분석기를 사용합니다.&lt;/span&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;저는 m1 이기에 아래 경로에 엘라스틱 서치가 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1690267061960&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cd /opt/homebrew/opt/elasticsearch-full
$ sudo ./bin/elasticsearch-plugin install analysis-nori&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;엘라스틱 서치는 &lt;span style=&quot;background-color: #ffffff; color: #343741; text-align: center;&quot;&gt;RESTful 검색 및 분석 엔진이라고 공식문서에 나와있죠?&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #343741; text-align: center;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #343741; text-align: center;&quot;&gt;그럼 api 요청을 날려서 인덱스를 만들면 되는데 설정을 노리에 맞게 세팅하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-25 오후 6.01.32.png&quot; data-origin-width=&quot;1003&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLxkxW/btsoYi30WWp/4dKIGr53KTYTMovNkKKYWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLxkxW/btsoYi30WWp/4dKIGr53KTYTMovNkKKYWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLxkxW/btsoYi30WWp/4dKIGr53KTYTMovNkKKYWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLxkxW%2FbtsoYi30WWp%2F4dKIGr53KTYTMovNkKKYWK%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;1003&quot; height=&quot;812&quot; data-filename=&quot;스크린샷 2023-07-25 오후 6.01.32.png&quot; data-origin-width=&quot;1003&quot; data-origin-height=&quot;812&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 차수에서 디비와 연동하며, 데이터를 넣고빼며 실제로 검색하는 방법을 알려드리겠습니다.&lt;/p&gt;</description>
      <category>Elasticsearch</category>
      <category>Elasticsearch</category>
      <category>m1</category>
      <category>nodejs</category>
      <category>NORI</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/57</guid>
      <comments>https://daily-coding-diary.tistory.com/57#entry57comment</comments>
      <pubDate>Tue, 25 Jul 2023 18:10:03 +0900</pubDate>
    </item>
    <item>
      <title>[Elasticsearch] 01. 검색엔진</title>
      <link>https://daily-coding-diary.tistory.com/56</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;검색엔진을 구현할때는 다양한 방법이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그 중에서 mysql like, mysql full-text-scan, elasticsearch 등이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;1. MySQL Like&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;일반적으로 mysql 등의 디비에서 키워드를 검색할때는 like연산자를 이용하여 일치하는 값을 검색합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그러나 like연산자를 이용하는 방식은 단어 또는 구문에 대한 검색에는 어느정도 한계가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만약 '크림 파스타' 라는 데이터가 있고, 유저가 &quot;크림파스타&quot; 라고 검색을 한다면 결과값은 나오지 않을 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;결과값이 나오게 하려면&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690264409427&quot; class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select * from search_warming where REPLACE(keyword, &quot; &quot;, &quot;&quot;) LIKE &quot;%크림파스타%&amp;rdquo;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이런식으로 조회를 해야 결과가 나올 것 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;또는 &quot;크림 머쉬룸 파스타&quot; 라는 데이터를&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;&quot;크림파스타&quot; 라고 검색을 한다면 이 또한 결과값이 나오지 않을 것이고,&lt;br /&gt;결과값이 나오게 하려면&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690264409428&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select * from search_warming
where keyword like '%크%' and keyword like '%림%' and keyword like '%파%' and keyword like '%스%' and keyword like '%타%';&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이런 요란한 방법을 써야할지도 모릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;심지어 이런 검색 결과를 중요도 순으로 정렬한다면?&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1690264409429&quot; class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select * from search_warming
where keyword like '%크%' and keyword like '%림%' and keyword like '%파%' and keyword like '%스%' and keyword like '%타%'
order by case
when keyword LIKE &quot;% 크림파스타 %&quot; then 1
when keyword LIKE &quot;%크림파스타%&quot;  then 2
else 3
end&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;키워드 하나만을 위해 이런 복잡한 로직이 쓰이게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;코드레벨에서 해결한다고 하더라도 로직이 복잡해지는건 마찬가지입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 like는 인덱싱되지 않은 컬럼에 적용하면 데이터베이스가 full scan을 사용하여 값을 찾고,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;인덱싱 됐다 해도 대부분의 인덱스 검색보다 효율적이지 못합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;레코드 수가 많아질 수록 성능이 저하되기때문에 사실상 사용하지 않는 것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 mysql 에서는 fulltext를 지원해줍니다.&amp;nbsp;&lt;/span&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;2. fulltext란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;인덱서는 텍스트를 입력으로 받아 텍스트 처리(어미 자르기, 중요하지 않은 단어 등)를 수행하고 모든 것을 인덱스에 저장합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이러한 인덱스의 구조는 매우 빠른 검색을 허용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;색인 검색 인터페이스인 검색 엔진은 클라이언트의 요청을 받아 구문을 처리하고 색인에서 검색합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;자연어 검색, 불린 모드 검색, 쿼리 확장 검색의 검색 방식을 지원합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;fulltext는 키가 개별 용어이고 관련 값이 해당 용어를 포함하는 레코드 세트인 인덱스를 사용합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이러한 레코드 집합을 결합하여 교차를 계산하도록 최적화가 되어있고, 검색 키워드와 얼마나 근접하게 일치하는지 정량화하는 순서 알고리즘을 제공 합니다.&amp;nbsp;&lt;/span&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;3. Elasticsearch&lt;/span&gt;란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;Elasticsearch는 시간이 갈수록 증가하는 문제를 처리하는 분산형 RESTful 검색 및 분석 엔진입니다. Elastic Stack의 핵심 제품인 Elasticsearch는 데이터를 중앙에 저장하여 손쉽게 확장되는 광속에 가까운 빠른 검색, 정교하게 조정된 정확도, 강력한 분석을 제공합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;1. 텍스트 검색에 매우 뛰어난 검색 성능을 보여주는데, 비교적 저사양의 노드로 구성된 클러스터로도 매우 많은 양의 텍스트를 빠르고 안정적으로 서비스가 가능합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;2.&amp;nbsp;JSON 문서 기반으로 데이터가 작성되며, 데이터 저장 시에 미리 정의하지 않은 컬럼도 인덱싱이 가능하여 스키마의 변경이 자유롭습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3.&amp;nbsp;검색엔진이 기반이기 때문에 키워드/결과 차원에 대한 스코어링이 기본적으로 탑재되어 있습니다. 따라서 원래 목적인 검색 결과/차원(dimension)에 따라 분류/집계(aggregation) 하고, 통계 값을 매기는 스코어링을 할 수 있어 리포트 &amp;ndash; 통계를 내는 목적으로도 이용이 가능합니다.&lt;/span&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;결론적으로 fulltext보다 ElasticSearch가 성능면에서 더 뛰어나고 빠르기때문에 ElasticSearch를 이용하여 검색엔진을 구현해보도록 하겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;</description>
      <category>Elasticsearch</category>
      <category>Elasticsearch</category>
      <category>fulltext</category>
      <category>mysql</category>
      <category>search</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/56</guid>
      <comments>https://daily-coding-diary.tistory.com/56#entry56comment</comments>
      <pubDate>Tue, 25 Jul 2023 15:05:52 +0900</pubDate>
    </item>
    <item>
      <title>[Node.js] prototype 사용예시</title>
      <link>https://daily-coding-diary.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 클래스 선언을 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1682499545185&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class User{}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 객체를 가져오는 방법은 아래의 양식이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1682499641484&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const user = new User()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 객체의 프로토타입은 User&lt;span style=&quot;background-color: #ffffff; color: #5a525f; text-align: left;&quot;&gt;.prototype 이 된다.&lt;/span&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;span style=&quot;background-color: #ffffff; color: #5a525f; text-align: left;&quot;&gt;3. 객체에 새로운 프로퍼티를 추가해줄 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1682499786228&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User.prototype.Hello = () =&amp;gt; {
    console.log('user')
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hello라는 메소드가 프로퍼티로써 추가되었다. 이 프로퍼티는 콘솔에 user 를 출력해준다.&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;4. user라는 이름으로 선언된 User 프로토타입 안에 있는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Hello 프로퍼티를 콘솔로 찍어본다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1682499909433&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(user.Hello())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user가 출력될 것이다.&lt;/p&gt;</description>
      <category>Node.js</category>
      <category>node</category>
      <category>Prototype</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/54</guid>
      <comments>https://daily-coding-diary.tistory.com/54#entry54comment</comments>
      <pubDate>Wed, 26 Apr 2023 18:15:01 +0900</pubDate>
    </item>
    <item>
      <title>[Node.js] prototype 이란</title>
      <link>https://daily-coding-diary.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;원문 : &lt;a href=&quot;http://www.tcpschool.com/javascript/js_object_prototype&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.tcpschool.com/javascript/js_object_prototype&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;자바스크립트의 모든 객체는 프로토타입(prototype)이라는 객체를 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;모든 객체는 그들의 프로토타입으로부터 프로퍼티와 메소드를 상속받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;이때 상속되는 정보를 제공하는 객체를 프로토타입(prototype)이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;프로토타입 체인(prototype chain)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 객체 이니셜라이저를 사용해&amp;nbsp;생성된 같은 타입의 객체들은 모두 같은 프로토타입을 가집니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;또한, new 연산자를 사용해 생성한 객체는 생성자의 프로토타입을 자신의 프로토타입으로 상속받습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682498874390&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var obj = new Object(); // 이 객체의 프로토타입은 Object.prototype입니다.

var arr = new Array();  // 이 객체의 프로토타입은 Array.prototype입니다.

var date = new Date();  // 이 객체의 프로토타입은 Date.prototype입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 Object.prototype 객체는 어떠한 프로토타입도&amp;nbsp;가지지 않으며, 아무런 프로퍼티도 상속받지 않습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;또한, 자바스크립트에 내장된 모든 생성자나 사용자 정의 생성자는 바로 이 객체를 프로토타입으로 가집니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682498903421&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var date = new Date(); // 이 객체는 Date.prototype 뿐만 아니라 Object.prototype도 프로토타입으로 가집니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이&amp;nbsp;프로토타입이 상속되는&amp;nbsp;가상의&amp;nbsp;연결 고리를&amp;nbsp;프로토타입 체인(prototype chain)이라고 합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Object.prototype 객체는 이러한&amp;nbsp;프로토타입 체인에서도 가장 상위에 존재하는 프로토타입입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;자바스크립트의 모든 객체는&amp;nbsp;Object.prototype 객체를 프로토타입으로&amp;nbsp;상속&lt;/span&gt;받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;프로토타입의 생성&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;프로토타입을&amp;nbsp;생성하는 가장 기본적인&amp;nbsp;방법은 객체 생성자 함수(object constructor function)를 작성하는 것입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;생성자 함수를 작성하고&amp;nbsp;new 연산자를 사용해&amp;nbsp;객체를 생성하면, 같은 프로토타입을 가지는 객체들을 생성할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682498970632&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Dog(color, name, age) { // 개에 관한 생성자 함수를 작성함.

    this.color = color;          // 색에 관한 프로퍼티

    this.name = name;            // 이름에 관한 프로퍼티

    this.age = age;              // 나이에 관한 프로퍼티

}

var myDog = new Dog(&quot;흰색&quot;, &quot;마루&quot;, 1); // 이 객체는 Dog라는 프로토타입을 가짐.

document.write(&quot;우리 집 강아지는 &quot; + myDog.name + &quot;라는 이름의 &quot; + myDog.color + &quot; 털이 매력적인 강아지입니다.&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;객체 생성자 함수를 작성할 때에는 관례상 이름의 첫 문자만을&amp;nbsp;대문자로 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;객체에 프로퍼티 및 메소드 추가&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이미 생성된 객체에 새로운 프로퍼티나&amp;nbsp;메소드를 추가하는 방법은 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682499019715&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Dog(color, name, age) {

    this.color = color;

    this.name = name;

    this.age = age;

}

var myDog = new Dog(&quot;흰색&quot;, &quot;마루&quot;, 1);

myDog.family = &quot;시베리안 허스키&quot;; // 품종에 관한 프로퍼티를 추가함.

myDog.breed = function() {        // 털색을 포함한 품종을 반환해 주는 메소드를 추가함.

    return this.color + &quot; &quot; + this.family;

}

document.write(&quot;우리 집 강아지는 &quot; + myDog.breed() + &quot;입니다.&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예제에서 새롭게 추가된 weight 프로퍼티와 breed() 메소드는 오직 myDog 인스턴스에만 추가됩니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이미 생성된 다른 Dog 객체나 차후에 생성되는 어떠한 다른 Dog 객체에도 추가되지 않습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;프로토타입에 프로퍼티 및 메소드 추가&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;프로토타입에 새로운 프로퍼티나 메소드를 추가하는 것은&amp;nbsp;객체에 추가할 때와는 다른 방법을 사용해야 합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;프로토타입의 경우에는 생성자 함수에 직접 추가해야만 이후에 생성되는 모든 다른 객체에도 적용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682499146683&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Dog(color, name, age) {

    this.color = color;

    this.name = name;

    this.age = age;

    this.family = &quot;시베리안 허스키&quot;; // 프로토타입에 프로퍼티를 추가할 때에는 기본값을 가지게 할 수 있음.

    this.breed = function() {

        return this.color + &quot; &quot; + this.family;

    };

}

var myDog = new Dog(&quot;흰색&quot;, &quot;마루&quot;, 1);

var hisDog = new Dog(&quot;갈색&quot;, &quot;콩이&quot;, 3);

document.write(&quot;우리 집 강아지는 &quot; + myDog.family + &quot;이고, 친구네 집 강아지도 &quot; + hisDog.family + &quot;입니다.&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;prototype 프로퍼티&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;prototype 프로퍼티를&amp;nbsp;이용하면 현재 존재하고 있는 프로토타입에 새로운 프로퍼티나 메소드를 손쉽게 추가할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682499247232&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Dog(color, name, age) {

    this.color = color;

    this.name = name;

    this.age = age;

}

// 현재 존재하고 있는 Dog 프로토타입에 family 프로퍼티를 추가함.

Dog.prototype.family = &quot;시베리안 허스키&quot;;

// 현재 존재하고 있는 Dog 프로토타입에 breed 메소드를 추가함.

Dog.prototype.breed = function() {

    return this.color + &quot; &quot; + this.family;

};

var myDog = new Dog(&quot;흰색&quot;, &quot;마루&quot;, 1);

var hisDog = new Dog(&quot;갈색&quot;, &quot;콩이&quot;, 3);

 

document.write(&quot;우리 집 강아지는 &quot; + myDog.family + &quot;이고, 친구네 집 강아지도 &quot; + hisDog.family + &quot;입니다.&quot;);

document.write(&quot;우리 집 강아지의 품종은 &quot; + myDog.breed() + &quot;입니다.&amp;lt;br&amp;gt;&quot;);

document.write(&quot;친구네 집 강아지의 품종은 &quot; + hisDog.breed() + &quot;입니다.&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;직접 생성한 프로토타입은&amp;nbsp;위와 같이&amp;nbsp;새로운 프로퍼티나 메소드를 마음껏 추가하거나 삭제할 수 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;물론 자바스크립트 표준 객체의 프로토타입도 임의로 수정할 수 있으나, 심각한 오류가 발생할 가능성이 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757; text-align: left;&quot;&gt;따라서&amp;nbsp;자바스크립트 표준 객체의 프로토타입은 수정해서는 안됩니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Node.js</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/53</guid>
      <comments>https://daily-coding-diary.tistory.com/53#entry53comment</comments>
      <pubDate>Wed, 26 Apr 2023 17:57:30 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 메모리 낭비 없이 전화번호 저장</title>
      <link>https://daily-coding-diary.tistory.com/50</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;int 형으로 전화번호를 적재하는 컬럼을 생성하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전화번호 01012345678 을 저장하면 1012345678 로 변환되어 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 보통 데이터 타입을 varchar 로 선언하는 경우가 많은데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;zerofill 설정을 해주면 값이 없으면 공백을 0으로 채워주기 때문에 01012345678가 정상적으로 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 전화번호는 절대 음수가 될 일이 없으므로&lt;span style=&quot;color: #333333;&quot;&gt; &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;UNSIGNED-&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;ZEROFILL 으로 설정해준다.&lt;/span&gt;&lt;/span&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_1680108989486&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;alter table user modify column number int(11) unsigned zerofill not null;&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;이 방식으로 하면 vachar 보다 메모리를 절약할 수 있어서 효율적이다.&lt;/p&gt;</description>
      <category>Database/mysql</category>
      <category>mysql</category>
      <category>SQL</category>
      <category>컬럼</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/50</guid>
      <comments>https://daily-coding-diary.tistory.com/50#entry50comment</comments>
      <pubDate>Thu, 30 Mar 2023 01:58:34 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] Count 성능 비교</title>
      <link>https://daily-coding-diary.tistory.com/47</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리문 성능 볼 수 있는 명령어는 &lt;span style=&quot;background-color: #282c34; color: #abb2bf;&quot;&gt;EXPLAIN&lt;/span&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;nbsp; count(*)&amp;nbsp;over()&amp;nbsp;as&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-17 오후 1.12.59.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zTy4q/btrZA10s7JQ/IcH0aiDQTJz5E9huWVTCL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zTy4q/btrZA10s7JQ/IcH0aiDQTJz5E9huWVTCL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zTy4q/btrZA10s7JQ/IcH0aiDQTJz5E9huWVTCL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzTy4q%2FbtrZA10s7JQ%2FIcH0aiDQTJz5E9huWVTCL1%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;768&quot; height=&quot;69&quot; data-filename=&quot;스크린샷 2023-02-17 오후 1.12.59.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;69&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;2. (select count(*) from TABLE) as count + group by&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-17 오후 1.14.07.png&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BLItz/btrZD0T3c3G/G0qTbBD1evUj0OArXWuh1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BLItz/btrZD0T3c3G/G0qTbBD1evUj0OArXWuh1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BLItz/btrZD0T3c3G/G0qTbBD1evUj0OArXWuh1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBLItz%2FbtrZD0T3c3G%2FG0qTbBD1evUj0OArXWuh1k%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;816&quot; height=&quot;69&quot; data-filename=&quot;스크린샷 2023-02-17 오후 1.14.07.png&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;69&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;gt; 서브쿼리 없이 count(*) over() as 하는 것이 성능이 더 좋음&lt;/p&gt;</description>
      <category>Database/mysql</category>
      <category>COUNT</category>
      <category>mysql</category>
      <category>Query</category>
      <category>SQL</category>
      <category>subquery</category>
      <category>서브쿼리</category>
      <category>성능비교</category>
      <author>hyun_ji</author>
      <guid isPermaLink="true">https://daily-coding-diary.tistory.com/47</guid>
      <comments>https://daily-coding-diary.tistory.com/47#entry47comment</comments>
      <pubDate>Fri, 17 Feb 2023 13:16:20 +0900</pubDate>
    </item>
  </channel>
</rss>