3

我将首先介绍我的应用程序:简单的投票应用程序,用户可以在其中创建和投票投票。简单的。
目前,我的 graphql 模式由用户类型、投票类型和投票类型组成,其中用户和投票与其投票具有一对多的关系,使用中继连接。投票类型除了参考其投票者和投票之外,还包含时间戳和实际投票值。

现在,据我了解,在规则 graphql 列表中使用连接的优点之一是能够在边缘存储数据(除了分页等等......)。我怎么能那样做?

如果确实有可能,我的计划是去掉投票类型,通过连接直接连接用户和他投票的投票,并将投票值和它的时间戳存储在连接边上。

如果重要,选民和他的投票之间的联系应该是双向的,即每个用户都连接到他投票的投票,每个投票都连接到它的选民。

4

2 回答 2

5

听起来你真的很接近拥有你想要的东西。我认为使用 Vote 类型作为 User 和 Poll 之间的中间人是一个很好的解决方案。这样做可以让您发出如下所示的查询:

// Direction 1: User -> Vote -> Poll
query GetUser($id: "abc") {
  getUser(id: $id) {
    username
    votes(first: 10) {
      edges {
        node {
          value
          poll {
            name
          }
        }
        cursor
      }
    }
  }
}

// Direction 2: Poll -> Vote -> User
query GetPoll($id: "xyz") {
  getPoll(id: $id) {
    name
    votes(first: 10) {
      edges {
        node {
          value
          user {
            username
          }
        }
        cursor
      }
    }
  }
}

在此示例中,您的投票类型是沿边缘存储信息的实体。您是正确的,连接优于列表的一个优点是您可以沿边缘存储信息,但我想说更大的好处是能够对大量对象进行分页。

要在服务器上实现这一点,您必须为 User 和 Poll 上的 Connection 字段(即上面示例中的“votes”字段)编写自定义解析方法。根据您存储数据的方式,这会发生变化,但这里有一些用于想法的伪代码。

type Vote {
  value: String,
  poll: Poll, // Both poll & user would have resolve functions to grab their respective object.
  user: User
}

type VoteEdge {
  node: Vote,
  cursor: String // an opaque cursor used in the 'before' & 'after' pagination args
}

type PageInfo {
  hasNextPage: Boolean,
  hasPreviousPage: Boolean
}

type VotesConnectionPayload {
  edges: [VoteEdge],
  pageInfo: PageInfo
}

const UserType = new GraphQLObjectType({
  name: 'User',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLID),
      description: "A unique identifier."
    },
    username: {
      type: new GraphQLNonNull(GraphQLString),
      description: "A username",
    },
    votes: {
      type: VotesConnectionPayload,
      description: "A paginated set of the user's votes",
      args: { // pagination args
        first: {
          type: GraphQLInt
        },
        after: {
          type: GraphQLString
        },
        last: {
          type: GraphQLInt
        },
        before: {
          type: GraphQLString
        }
      }
      resolve: (parent, paginationArgs, ctxt) => {

        // You can pass a reference to your data source in the ctxt.
        const db = ctxt.db;

        // Go get the full set of votes for my user. Preferably this returns a cursor
        // to the set so you don't pull everything over the network
        return db.getVotesForUser(parent.id).then(votes => {

          // Assume we have a pagination function that applies the pagination args
          // See https://facebook.github.io/relay/graphql/connections.htm for more details
          return paginate(votes, paginationArgs);

        }).then((paginatedVotes, pageInfo) => {

          // Format the votes as a connection payload.
          const edges = paginatedVotes.map(vote => {

            // There are many ways to handle cursors but lets assume
            // we have a magic function that gets one.
            return {
              cursor: getCursor(vote),
              node: vote
            }

          });

          return {
            edges: edges,
            pageInfo: pageInfo
          }
        })
      }
    }
  })
});

您必须在您的 Poll 类型中为反向执行类似的操作。要将对象添加到连接中,您需要做的就是创建一个指向正确用户和帖子的投票对象。db.getVotesForUser() 方法应该足够聪明,可以意识到这是一个一对多连接,然后可以拉取正确的对象。

创建处理连接的标准方式可能是一项艰巨的任务,但幸运的是,有一些服务可以帮助您开始使用 GraphQL,而无需自己实现所有后端逻辑。我为这样的服务https://scaphold.io工作,如果您有兴趣,很乐意与您进一步讨论此解决方案!

于 2016-06-24T00:12:51.257 回答
3

这可能最好使用Michael Paris 的回答Vote中描述的单独实体进行建模,但是,为了解决更一般的问题“我如何在边缘上定义其他字段?”,请注意,您可以传递到graphql 中的函数-继电器模块edgeFieldsconnectionDefinitions

测试套件中有一个示例:

var {connectionType: friendConnection} = connectionDefinitions({
  name: 'Friend',
  nodeType: userType,
  resolveNode: edge => allUsers[edge.node],
  edgeFields: () => ({
    friendshipTime: {
      type: GraphQLString,
      resolve: () => 'Yesterday'
    }
  }),
  connectionFields: () => ({
    totalCount: {
      type: GraphQLInt,
      resolve: () => allUsers.length - 1
    }
  }),
});
于 2016-06-27T16:23:19.323 回答