仅在graphql需要时才如何获取特定字段?

时间:2019-12-03 01:54:46

标签: graphql nestjs type-graphql

我已经开始学习NestJs和GraphQL,并创建了一个简单的后端:

我有帖子:

import { Field, Int, ObjectType } from 'type-graphql';

@ObjectType()
export class Post {

    constructor ({ id, title }) {
        this.id = id;
        this.title = title;
    }

    @Field(type => Int, { nullable: true })
    id: number;

    @Field(type => String)
    title: string;

}

我有用户

import { Field, Int, ObjectType } from 'type-graphql';
import { Post } from './post';

@ObjectType()
export class User {

    constructor({ id, name, postIds }) {
        this.id = id;
        this.name = name;
        this.postIds = postIds;
    }

    @Field(type => Int)
    id: number;

    @Field(type => String)
    name: string;

    @Field(type => [Int])
    postIds: number[];

    // in case 'postIds' populating
    @Field(type => [Post])
    posts: Post[];
}

然后NestJS(我认为type-graphql库做到了)为我生成了schema.gql文件:

# -----------------------------------------------
# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!!
# !!!   DO NOT MODIFY THIS FILE BY YOURSELF   !!!
# -----------------------------------------------

type Post {
  id: Int
  title: String!
}

type Query {
  user(id: Int!): User!
}

type User {
  id: Int!
  name: String!
  postIds: [Int!]!
  posts: [Post!]!
}

最后一个带有UserResolver的文件:

import { Int, Resolver } from 'type-graphql';
import { Args, Query } from '@nestjs/graphql';
import { User } from './models/user';
import { Post } from './models/post';

const post1 = new Post({ id: 1, title: 'title_1' });
const post2 = new Post({ id: 2, title: 'title_2' });
const post3 = new Post({ id: 3, title: 'title_3' });
const user1 = new User({ id: 1, name: 'Alex', postIds: [post1.id, post2.id] });
const user2 = new User({ id: 2, name: 'Kate', postIds: [post3.id] });
const allUsers = [user1, user2];
const allPosts = [post1, post2, post3];

@Resolver()
export class UserResolver {

    @Query(returns => User)
    user(@Args({ name: 'id', type: () => Int }) id) {
        const currentUser = allUsers.find(u => u.id === id);

        // please, remember next part of code
        currentUser.posts = [];
        currentUser.postIds.forEach(postId => {
            const currentPost = allPosts.find(p => p.id === postId);
            currentUser.posts.push(currentPost);
        });
        return currentUser;
    }

}

就这些。这很简单。现在,我可以请求下一个:

{        
    user(id:1) {
        name
        posts {
            title
        }
    }
}

它有效。但是有一些问题。如果是下一个请求...

{
    user(id:1) {
        name
        postIds
        #posts aren't required anymore
    }
}

...下一条代码仍然执行

        currentUser.posts = [];
        currentUser.postIds.forEach(postId => {
            const currentPost = allPosts.find(p => p.id === postId);
            currentUser.posts.push(currentPost);
        });

我认为这是不对的。 graphql的想法是仅采用查询中描述的必要数据。就我而言,我们得到posts,然后将其切断。如果将来会有大量的User.Post.IntroImage.Comment.User嵌套,那么这将无效。

请告诉我该怎么做?

1 个答案:

答案 0 :(得分:2)

我找到了答案:)

import { Args, Parent, Query, ResolveProperty, Resolver } from '@nestjs/graphql';
import { User } from './models/user';
import { Post } from './models/post';

const post1 = new Post({ id: 1, title: 'title_1' });
const post2 = new Post({ id: 2, title: 'title_2' });
const post3 = new Post({ id: 3, title: 'title_3' });
const user1 = new User({ id: 1, name: 'Alex', postIds: [post1.id, post2.id] });
const user2 = new User({ id: 2, name: 'Kate', postIds: [post3.id] });
const allUsers = [user1, user2];
const allPosts = [post1, post2, post3];

@Resolver(of => User)
export class UserResolver {
    @Query(returns => User)
    user(@Args('id') id: number) {
        return allUsers.find(u => u.id === id);
    }

    @ResolveProperty()
    async posts(@Parent() user) {
        return user.postIds.map(postId => {
            return allPosts.find(p => p.id === postId);
        });
    }
}

我只需要添加@ResolveProperty并在需要时执行graphql库。