그저 내가 되었고

🎯Node.js + mongoDB:: 중첩 조건으로 게시글 필터링하기 본문

개발/DB

🎯Node.js + mongoDB:: 중첩 조건으로 게시글 필터링하기

hyuunii 2022. 11. 25. 14:35

💫 로고 너무 이쁘다,, 영롱🫢

 

1. 하고자 한 것: 위처럼 내가 찾고자 하는 조건(위치, 날짜, 시간, 인원)을 한꺼번에 받아서 게시글 필터링

 

 

2. 유의미한 구글링 키워드: mongodb overlap find, mongodb document query overlap find

 

 

3. 사용한 방법:

쿼리:: 쿼리로 find() 함수 이용하기; find() 함수 기본형에 쿼리를 추가해서 이용하면 다양한 조건으로 검색이 가능함.

<비교 쿼리>

쿼리 설명
$eq equals, 일치하는 값을 찾는다.
$gt greater than, 지정된 값보다 큰 값을 찾는다.
$gte greater than or equals, 크거나 같은 값을 찾는다.
$lt less than, 지정된 값보다 작은 값을 찾는다.
$lte less than or equals, 작거나 같은 값을 찾는다.
$ne not equal, 일치하지 않는 모든 값을 찾는다.($eq의 부정)
$in 배열에 지정된 값 중 하나와 일치한 값을 찾는다.
$nin 배열에 지정된 값과 일치하지 않는 값을 찾는다.

 

<논리 쿼리>

조건과 쿼리에 따른 결과를 반환하며, 조건은 2개 이상이 올 수 있음.

쿼리 설명
$or 조건들 중 하나라도 true면 반환
(true: 조건과 일치, false: 조건과 불일치)
$and 조건들이 모두 true일 때 반환
$not 조건이 false일 때 반환
$nor 조건들이 모두 false일 때 반환

 

lodash 라이브러리:: for 중복 제거(혹시.. 혹시 모를 중복 제거하기 위해)

1) npm i --save lodash

2) controllers/posts 윗부분에 삽입

const _ = require('lodash');

3) 코드에서 사용할 때는 이런 식

let posts = [...filter]
            posts = _.uniqBy(posts, "_id");  //중복 제거(Library Lodash)

 

4. 코드

posts.router.js

router.post("/filterPosts", postsController.filterPosts); //게시글 필터링

 

req.body //프런트에서 사용하는 라이브러리가 시간&날짜를 한꺼번에 입력받는 애라고 함. 그래서 원래는 date, time 따로 받도록 만들었다가 time 하나만 받는 걸로 코드 수정.

{
"map" : "서대문구",
"time" : ["2022-11-29T09", "2022-11-29T19"],
"partyMember" : ["2", "6"]
}

 

controllers/posts.js

const Posts = require("../schema/posts");
const _ = require('lodash');
//게시글 필터링
    filterPosts = async (req, res, next) => {
        try {
            const {map, time, partyMember} = req.body;
            const filterPosts = await this.postsService.filterPosts(map, time, partyMember);
            res.status(200).json({data: filterPosts, message: "게시글 필터링 완료"});
        } catch (e) {
            res.status(e.status || 400).json({statusCode: e.status, message: e.message });
        }
    }

 

services/posts.js

 //게시글 필터링
    filterPosts = async(map, time, partyMember) => {
        const filteredPostsData = await this.postsRepository.filterPosts(map, time, partyMember);

        for (let i = 0 ; i < filteredPostsData.length; i++) {
            const membersStatus = (filteredPostsData[i].confirmMember.length / filteredPostsData[i].partyMember);

            if (membersStatus > 0 && membersStatus <= 0.3) {
                filteredPostsData[i]["memberStatus"] = 0;
            }
            else if (membersStatus > 0.3 && membersStatus <= 0.6) {
                filteredPostsData[i]["memberStatus"] = 1;
            }
           else if (membersStatus > 0.6 && membersStatus <= 0.9) {
                filteredPostsData[i]["memberStatus"] = 2;
            } else {
                filteredPostsData[i]["memberStatus"] = 3;
            }
        }
        return filteredPostsData
    }

 

repositories/posts.js

//게시글 필터링
    filterPosts = async (map, time, partyMember) => {
        const filter = await Posts.find(
            {
                $and: [
                    {map: {$regex: new RegExp(`${map}`, "i")}},
                    {time: {$gte: time[0], $lte: time[1]}},
                    {partyMember: {$gte: partyMember[0], $lte: partyMember[1]}}
                ]
            });
        for (let i = 0; i < filter.length; i++) {
            const findUser = await Users.findOne({userId: filter[i].userId})
            filter[i]['userAvatar'] = findUser.userAvatar;
        }
    return filter;
    }

 

 

5. 더 생각해볼 점:  

✓get method에서 req.body 사용 가? 불가?:

처음에는 get으로 코드를 짰다가 swagger에서 오류 봉착(typeerror: failed to execute 'fetch' on 'window': request with get/head method cannot have body.)하여 post로 method를 변경했다.

postman에서는 아무 문제 없이 돌아갔었는데 swagger에서는 안되는걸 보니 특정 클라이언트에서는 get body가 무시되는 경우가 있는 것 같다. 

✓req.body가 아닌 req.params로 구현하기: 네이버 쇼핑 상세 필터링, 11번가 쇼핑 상세 필터링 등은 전부 params를 쓴다고 함

↳참고; https://velog.io/@joonsikyang/React-Project-URL-parameters-Query-parameters