12-3. 포스트 받아 올때 liked 값 설정해주기

이제 유저가 포스트 목록을 받아 올 때, API 를 요청한 유저가 각 포스트들을 좋아했는지, 혹은 좋아하지 않았는지 알려주는 liked 값을 설정해주도록 하겠습니다. 그러기 위해선, Post 모델의 list 메소드를 실행하게 될 때, like API 를 사용 했을 때 처럼 projection 값을 사용해주어야합니다.

하지만, 지금의 경우에는 likes 와 likesCount 말고도 다른 정보들을 불러와야 하니, 각 키에 대하여 값을 1로 설정해주세요.

이제, list 메소드를, self 값 (API 요청자의 username)이 주어졌을 때는, projection 값을 설정하고, 그렇지 않을때는 기본 설정인 { } 으로 전달하게끔 수정을 하겠습니다.

src/model/post.js

// 포스트 리스팅
Post.statics.list = function({cursor, username, self}) {
    // cursor, username 값의 존재 유무에 따라 쿼리가 유동적으로 설정됩니다.
    const query = Object.assign(
        { }, 
        cursor ? { _id: { $lt: cursor } } : { },
        username ? { username } : { }
    );

    // API 를 호출한 username (self) 값이 존재하면 likes 에 해당 username 이 있는지 체크
    const projection = self ? {
        count: 1,
        username: 1,
        content: 1,
        comments: 1,
        likes: {
            '$elemMatch': { '$eq': self }
        },
        likesCount: 1,
        createdAt: 1
    } : { };

    return this.find(query, projection)
        .sort({_id: -1}) // _id 역순
        .limit(20) // 20개로 제한
        .exec();
};

모델을 수정하고 난 다음엔 API 도 수정을 해줍니다.

src/api/posts/posts.controller.js

exports.list = async (ctx) => {
    const { cursor, username } = ctx.query; // URL 쿼리에서 cursor 와 username 값을 읽는다

    // ObjectId 검증
    if(cursor && !ObjectId.isValid(cursor)) {
        ctx.status = 400; // Bad Request
        return;    
    }

    // API 를 호출한 유저의 정보를 가져옵니다
    const { user } = ctx.request;
    const self = user ? user.username : null; // 로그인한 유저라면 username 값을 self 에 넣어줍니다

    let posts = null;
    try {
        posts = await Post.list({cursor, username, self}); 
    } catch (e) {
        ctx.throw(500, e);
    }

    // 만약에 불러올 데이터가 20개라면, 그 다음 데이터들이 더 있을 수 있습니다.
    // 현재 불러온 데이터 중 가장 마지막 데이터를 기점으로 데이터를 추가적으로 로딩하는 API 의 주소를 만들어줍니다.
    // username 이 주어졌으면 username 도 포함시켜주어야합니다.
    const next = posts.length === 20 ? `/api/posts/?${username ? `username=${username}&` : ''}cursor=${posts[19]._id}` : null;


    // 좋아요 했는지 확인
    function checkLiked(post) {
        // posts 에 스키마에 속하지 않은 값을 추가해주려면 toObject() 를 해주어야합니다.
        // 혹은, 쿼리를 하게 될 떄 .lean().exec() 의 형식으로 해야합니다.
        post = post.toObject(); 
        // 비로그인 상태라면 false
        // 배열에 아이템이 있다면, 자신의 아이디가 들어있다는 뜻이니 true
        const checked = Object.assign(post, { liked: user !== null && post.likes.length > 0 }); 
        delete checked.likes; // likes key 제거
        return checked;
    }

    posts = posts.map(checkLiked); // map 을 통하여 각 포스트를 변형시켜줍니다


    //  데이터와, 그 다음 데이터를 가져오는 API 주소를 응답합니다.
    ctx.body = {
        next, 
        data: posts
    };
};

이제 포스트 리스트 API 를 테스트해보세요.

GET http://localhost:4000/api/posts
{
    "next": "/api/posts/?cursor=596281a73ff39d67043b6776",
    "data": [
        {
            "_id": "596281e63ff39d67043b6789",
            "count": 66,
            "username": "tester",
            "content": "testing",
            "__v": 0,
            "comments": [],
            "likesCount": 0,
            "createdAt": "2017-07-09T19:20:06.428Z",
            "liked": false
        },
        (...)
    ]
}

이런식으로, likes 배열 대신에 liked 값이 나타나게 됩니다. 좋아요를 했다면 true 가 되고 그렇지 않다면 false 가 되겠지요. 추가적으로, 새 포스트를 작성 할 때에도 liked 값을 기본적으로 false 로 설정하여 보여주도록 하겠습니다.

src/api/posts/posts.contorller.js

exports.write = async (ctx) => {
    (...)

    /* 포스트 write 메소드 호출 */
    let post;
    try {
        post = await Post.write({
            count,
            username: user.profile.username,
            content
        });
        await account.increaseThoughtCount();
    } catch (e) {
        ctx.throw(500, e);
    }

    // post 에 liked 값 false 로 설정
    post = post.toJSON();
    delete post.likes;
    post.liked = false;

    /* 포스트 정보 반환 */
    ctx.body = post;

    /* 데이터를 리덕스 액션 형식으로 전송 */
    publisher.publish('posts', JSON.stringify({
        type: 'posts/RECEIVE_NEW_POST',
        payload: post
    }));
};

이제 포스트를 작성하게되면, 다음과 같이 liked 값이 false 가 된 객체를 응답하게 됩니다.

{
    "__v": 0,
    "count": 1,
    "username": "tester",
    "content": "testing",
    "_id": "596545ee66ac744ab09d4272",
    "comments": [],
    "likesCount": 0,
    "createdAt": "2017-07-11T21:41:02.798Z",
    "liked": false
}

results matching ""

    No results matching ""