ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 항해 99 5기 TIL_85
    항해 99 2022. 4. 5. 03:48

    ▶ Today I Learned

     

    <실전 프로젝트>

     

    [방 제목, 태그, 카테고리로 검색하기 - 문제 해결]

     

    지난 주 토요일 구현 후 오랜 시간 끝에 드디어 구현했다.

    코드는 아래와 같다.

     // 개발자 꿈나물 세번째 시도
    
    /* 제목, 카테고리, 태그 순으로 조건에 부합하는 방 모두 가져오기
    겹치는 방이 없도록 배열 내 중복 제거
    시간 순과 내림차순으로 정렬
    이떄 offset과 roomSearchingLimit은 적용하지 않음, 태그로 찾은 방, 카테고리로 찾은 방,
    제목으로 찾은 방 간에 시간차가 있기 때문,
    예를 들어 각각 7개의 방을 찾았는데 시간 순으로 따졌을 때 태그 2, 카테고리 2개, 제목 3개 총 7개의 방이 노출됨,
    여기서 offset으로 각각의 Room.findAll 마다 방을 7개씩 건너가 버리면 중간에 생략되는 방들이 생김
    그렇기에 조건에 부합하는 모든 방을 다 찾은 다음 7개, 8개, 8개... 이렇게 보여주는 게 맞음 */
    
              const roomsByTitle = await Room.findAll({
                  where: {
                    [Op.or]: [
                    {title: { [Op.like]: `%${query}%` }},
                    ],
                  },
                  attributes: [
                    "id",
                    "title",
                    "isSecret",
                    "createdAt",
                    "likeCnt",
                    "participantCnt",
                  ],
                  include: [
                    {
                      model: Category,
                      attributes: ["id", "name"],
                    },
                    {
                      model: Tag,
                      as: "Tags",
                      attributes: ["id", "name"],
                      through: { attributes: [] },
                    },
                  ],
                  order: [["createdAt", "desc"]],
                });
            
                const roomsByTag = await Room.findAll({
                  attributes: [
                    "id",
                    "title",
                    "isSecret",
                    "createdAt",
                    "likeCnt",
                    "participantCnt",
                  ],
                  include: [
                    {
                      model: Category,
                      attributes: ["id", "name"],
                    },
                    {
                      model: Tag,
                      as: "Tags",
                      attributes: ["id", "name"],
                      through: { attributes: [] },
                      where: {
                        [Op.or]: [ 
                          {name: {[Op.like]: `%${query}%` }
                        }
                      ]}
                    },
                  ],
                  order: [["createdAt", "desc"]],
                });
    
                const roomsByCategory = await Room.findAll({
                  attributes: [
                    "id",
                    "title",
                    "isSecret",
                    "createdAt",
                    "likeCnt",
                    "participantCnt",
                  ],
                  include: [
                    {
                      model: Category,
                      attributes: ["id", "name"],
                      where: {
                        [Op.or]: [ 
                          {name: {[Op.like]: `%${query}%` }
                        }
                      ]}
                    },
                    {
                      model: Tag,
                      as: "Tags",
                      attributes: ["id", "name"],
                      through: { attributes: [] },
                    },
                  ],
                  order: [["createdAt", "desc"]],
                });
              
    
                // 구한 방 목록 배열 모두 합치기
                
                let searchRooms = []
                searchRooms = searchRooms.concat(roomsByTitle, roomsByTag, roomsByCategory)
              
                // 중복된 방 데이터 제거
                
                let uniqueRooms = []
                let uniqueRoomsTitles = []
    
                    searchRooms.map((v) => {if (!uniqueRoomsTitles.includes(v.dataValues.title)) {
                    uniqueRooms.push(v)
                    uniqueRoomsTitles.push(v.dataValues.title)
                    }
                 }
              )
            
                // cf) 이렇게 비교하는 것들도 가능
                // if(uniqueRooms[i].dataValues.createdAt.getTime() === uniqueRooms[i+1].dataValues.createdAt.getTime()) 
                // if( JSON.stringify(uniqueRooms[i].dataValues) === JSON.stringify(uniqueRooms[i+1].dataValues) )
                // 객체 간 직접적 비교는 안되기에 객체를 문자열로 바꿔줌
    
    
              // 날짜 순으로 내림차순 (최신 글이 위에 배치되도록 함)
              
              let tempSaved; // 배열 값 위치 변환에 사용되는 변수
    
                for (let i = 0 ; i < uniqueRooms.length - 1 ; i++) {
                if(uniqueRooms[i].dataValues.createdAt < uniqueRooms[i+1].dataValues.createdAt) {
                  tempSaved = uniqueRooms[i]
                  uniqueRooms[i] = uniqueRooms[i+1]
                  uniqueRooms[i+1] = tempSaved
                  i = -1 // 서로의 앞뒤만 고려하는 것이 아닌 전체 수 내에서의 대소를 비교하기 위해 앞뒤 비교 후 인덱스를 -1로 지정해주어 다시 시작
                }
                }
                
                // 그 중 처음엔 7개, 그 다음엔 8개씩 보여주도록 하기
    
                if (page === 1) {
                  if (uniqueRooms.length < 7) { // 결과물이 7개 미만인 경우
                    rooms = uniqueRooms.slice(0,uniqueRooms.length)
                  } else {
                    rooms = uniqueRooms.slice(0, 7)
                  }
                } else {
                  rooms  = uniqueRooms.slice(7 + 8*(page-2), 7 + 8*(page-1))
                }
              
              break;
          };
    
          return res.status(200).json({
            isSuccess: true,
            data: rooms,
          });
        }),

     

    Sequelize에만 의존하는 방법으로는 해결책을 찾을 수 없었다.

    그리하여 처음 착안했던 제목, 태그, 카테고리 별로 방을 찾은 다음 각각을 중복된 값을 제거하여 합쳤다.

    시간 복잡도가 염려되긴 하였지만 현재 서비스 규모에서는 빠르게 작동되어 문제없었으며

    결국 어떤 기능을 사용하더라도 제목, 태그, 카테고리 테이블을 모두 검사해야하기에 소요 시간이 비슷할 것이라는 생각이 들었다.

    물론 추후 좀 더 효율적인 방식을 알게 된다면 새롭게 적용해보고 싶다.

     

    이 과정에서 사용한 concat()은 두 개 이상의 배열을 합칠 때 사용하는 함수이며 기존의 배열은 바꾸지 않은 채

    새로운 배열을 반환한다. 이 때 중복 값을 제거해주지는 않는다.

    따라서 그 아래 작성한 코드와 같이 searchRooms라는 배열의 구성요소 중 이미 push로 집어넣은 title들은

    배제하여 중복 값을 제거한 배열을 최종적으로 반환하게 된다.

     

    concat() MDN 공식문서 설명

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

     

    문제 해결 :)

     

    거의 7시간 ~ 8시간은 걸린 것 같다.

    막상 짜놓고 보니 좀 오래 걸린 것 같지만 17번의 커밋과 갖은 예외처리 고민,

    자바스크립트 문법 공부 등으로 이뤄낸 성과이다.

    덕분에 제목, 태그, 카테고리 그 어느 것 하나라도 일치하면 검색결과에 보여주고 중복된 결과는 없다.

    방 갯수도 처음엔 7개, 그 다음엔 8개를 잘 보여준다.

     

     

    [배열 중복 제거]

     

    누군가의 글에서 배열을 Set이라는 객체를 이용하면

    중복 값을 제거해준다는 글을 보았다.

    그것을 따라해보았는데 아래와 같이 객체가 중복된 경우는 저절로 제거되지 않는다.

    const arr = [{name: "tom"}, {name: "anna"}, {name: "tom"} ] 
    
    let set = new Set (arr)
    
    console.log(set)
    console.log([...set])
    
    const arr2 = [1,2,1] 
    
    let set2 = new Set (arr2)
    
    console.log(set2)
    console.log([...set2])
    
    
    // 콘솔 결과
    Set { { name: 'tom' }, { name: 'anna' }, { name: 'tom' } }
    [ { name: 'tom' }, { name: 'anna' }, { name: 'tom' } ]
    Set { 1, 2 }
    [ 1, 2 ]

     

    이 외에도 객체끼리 ===를 써서 비교해보았을 때는 똑같이 생겨도 true가 나오지 않았다.

    이에 대해서는 공부가 더 필요할 듯 하다. (예전 기억에 값은 같아도 저장된 메모리의 위치가 달라서? 라는 말을 들은 것 같기도 하다. 찾아보아야겠다.)

     

    ▶ 느낀 점

     

    오늘도 많은 것을 해결한 것은 아니지만 틈틈이 팀원들의 요청에 응답하고 소통하며 부탁받은 것도 처리해나갔고

    내가 맡은 버그를 중점적으로 하여 결국 해결해냈다.

    나름 뿌듯한 하루였다.

    기분 좋게 자고 내일도 열심히 해야겠다 :)

     

    ▶ 공부 시 참고 링크들

     

     

    배열 내 중복 값 제거하는 방법

    https://hianna.tistory.com/422

     

    [Javascript] 배열 중복 제거하는 3가지 방법

    Javascript의 배열에서 중복 되는 값을 제거하는 3가지 방법을 알아보도록 하겠습니다. 1. Set 2. indexOf(), filter() 3. forEach(), includes() 1. Set Javascript에서 Set 객체를 이용하면 중복없는 데이터를..

    hianna.tistory.com

     

    배열의 요소끼리 합하여 하나의 배열을 만들 때 쓰는 concat()

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

     

    Array.prototype.concat() - JavaScript | MDN

    The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.

    developer.mozilla.org

    자바스크립트 객체 비교

    https://www.delftstack.com/ko/howto/javascript/compare-objects-javascript/#:~:text=%EB%8C%80%ED%95%B4%20%EC%84%A4%EB%AA%85%ED%95%A9%EB%8B%88%EB%8B%A4.-,JavaScript%EC%9D%98%20JSON.stringify()%20%ED%95%A8%EC%88%98%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC%20%EA%B0%9D%EC%B2%B4,%EC%9C%A0%ED%98%95%EC%9D%B4%20%EB%90%A0%20%EC%88%98%20%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4. 

     

    JavaScript에서 객체 비교

    수동으로 또는 JavaScript의 JSON.stringify() 함수를 사용하여 객체를 비교할 수 있습니다.

    www.delftstack.com

     

    '항해 99' 카테고리의 다른 글

    항해 99 5기 TIL_87  (0) 2022.04.07
    항해 99 5기 TIL_86  (0) 2022.04.07
    항해 99 5기 WIL_12  (0) 2022.04.03
    항해 99 5기 TIL_84  (0) 2022.04.03
    항해 99 5기 TIL_83  (0) 2022.04.03
Designed by Tistory.