Instagramクローンエンコーディング5日目-BE


#2.6 Followers
@Relationを使用して、一方向関係の関係を指定できます.
たとえば、BでAに従うと、AのFolwersに自動的にBが追加されます.
A.followers[ B ]
B.following[ A ]
schema.prismaでユーザーモデルに追従者と追従者を追加し、移行します.
//schema.prisma
model User {
  .
  .
  . // relation끼리의 이름이 같아야한다.
  followers User[]   @relation("FollowRelation", references: [id])
  following User[]   @relation("FollowRelation", references: [id])
  .
  .
}
followUserのtypeDefsと解析器を作成します.
ユーザー名でフォロー
//followUser.typeDefs.js
import { gql } from "apollo-server-express";

export default gql`
    type followUserResult{
        ok: Boolean!
        error: String
    }
    type  Mutation{
       followUser(username: String!): followUserResult!
   }
`;
接続時に接続できるのは、唯一のフィールドのみです.
接続の代わりにdisconnectを使用すると、接続が切断されます.すなわち、unfollow.
//followUser.resolver.js
const resolverFn = async (_, { username }, { loggedInUser }) => {
    const isUser = client.user.findUnique({ where: { username } });
    if (!isUser) {
        return {
            ok: false,
            error: "That user does not exist",
        };
    }
    await client.user.update({
        where: {
            id: loggedInUser.id,
        },
        data: {
            following: {
                connect: {
                    username,
                }
            }
        }
    });
    return {
        ok: true
    };
};
#2.7 See Followers & Following
includeはあなたに欲しい関係を持たせます.
prismaは、データベースに大量のデータをロードするとサーバに負担をかけるため、ロード関係はほとんどありません.
少量のデータをインポートする場合は、includeで直接ロードできます.
//seeProfile.resolvers.js
import client from "../../client";

export default {
    Query: {
        seeProfile: (_, { username }) => client.user.findUnique({
            where: {
                username,
            },
            include: {
                following: true,
                followers: true,
            }
        })
    }
};
#2.8 Paginations
上述したように、一度に複数のデータが読み込まれ、1ページずつ読み込まれることをページングと呼ぶ.
Paginationには2種類あります.
Offset Pagination
利点:必要なページに移動できます.
欠点:200000個のデータをスキップして10個のデータをインポートする場合は、200000個のデータをインポートする必要があります.
//seeFollowers.resolvers.js
import client from "../../client"

export default {
    Query: {
        seeFollowers: async (_, { username, page }) => {
            const isUser = await client.user.findUnique({
              where: { username }, select: { id: true } 
            }); //user 존재여부만 확인할 때는 user의 모든 data를 가져오지 않고 id만 가져온다.
            if (!isUser) {
                return {
                    ok: false,
                    error: "User is not found"
                };
            }
            const followers = await client.user
            .findUnique({ where: { username } })
            .followers({
                take: 5,
                skip: (page - 1) * 5,
            });
          //user들 중 username을 following한 사람 수를 찾는 query
            const totalFollowers = await client.user.count({
                where: { following: { some: { username, } } }
            });// 배열을 다 가져올 필요 없이 개수를 세고 count한 수만 가져온다.
            return {
                ok: true,
                followers,
                totalPages: Math.ceil(totalFollowers / 5),
            };
        }
    }
};
Cursor-based Pagination
長所:規模を拡大しやすい.(無限スクロール用)
欠点:必要なページに移動できません.
LastIdを取得し、最後のIDからskipまで、次からtake数を取得します.
最初からlastidがなければskipは0,cursorは無である.
// seeFollowing.resolvers.js
import client from "../../client"

export default {
    Query: {
        seeFollowing: async (_, { username, lastId }) => {
            const isUser = await client.user.findUnique({ where: { username }, select: { id: true } });
            if (!isUser) {
                return {
                    ok: false,
                    error: "User is not found"
                };
            }
            const following = await client.user.findUnique({ where: { username } }).following({
                take: 5,
                skip: lastId ? 1 : 0,
                ...(lastId && { cursor: { id: lastId } })
            });
            return {
                ok: true,
                following,
            };
        }
    }
};
#2.9 Computed Field
計算フィールドはgraphqlsechemaで定義されていますが、データベースにはありません.要求が受信されるたびに計算されます.
queryでuserを要求するとgraphqlはDBからuserを取得し、データベースにないフィールドをチェックし、解析器で検索します.見つかった場合は、この解析器をDBからインポートしたuserとして実行します.
解析器の最初のパラメータはルートで、親を表します.親プレイヤーとトークンで登録したプレイヤーを比較することができます.
// users.resolvers.js
import client from "../client";

export default {
    User: {
        totalFollowing: ({ id }) => //following 수
            client.user.count({
                where: {
                    followers: {
                        some: {
                            id,
                        }
                    }
                }
            }),
        totalFollowers: ({ id }) => //follower 수
            client.user.count({
                where: {
                    following: {
                        some: {
                            id,
                        }
                    }
                }
            }), //user가 로그인한 자신인지 확인
        isMe: ({ id }, _, { loggedInUser }) => {
            if (!loggedInUser) {
                return false;
            }
            return id === loggedInUser.id;
        }, // user가 follow한 사람인지 확인
        isFollowing: async ({ id }, _, { loggedInUser }) => {
            if (!loggedInUser) {
                return false;
            }
            const exist = await client.user.count({
                where: {
                    username: loggedInUser.username,
                    following: {
                        some: {
                            id
                        }
                    }
                }
            });
            return Boolean(exist);
        }
    }
};