React Relay:向边缘添加数据
React Relay: Adding data to edges
我将首先介绍我的应用程序:简单的投票应用程序,用户可以在其中创建民意调查并进行投票。简单。
目前我的 graphql 模式由用户类型、投票类型和投票类型组成,其中用户和投票与其投票具有一对多关系,使用中继连接。
投票类型包含对其选民和民意调查的引用、时间戳和实际投票值。
现在,据我了解,在规则 graphql 列表上使用连接的优势之一是能够在边缘存储数据(除了分页等...)。
我该怎么做?
如果确实可行,我的计划是摆脱投票类型,直接通过连接连接用户和他投票的民意调查,并将投票值及其时间戳存储在连接边上。
如果重要的话,选民和他的民意调查之间的连接应该是双向的,即每个用户都连接到他投票的民意调查,每个民意调查都连接到它的选民。
听起来您离想要的东西真的很近了。我认为使用 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
}
}
}
}
在此示例中,您的投票类型是沿边存储信息的实体。 Connections 优于 Lists 的一个优势是你可以沿边缘存储信息,这是正确的,但我想说更大的好处是能够对大型对象集进行分页。
要在服务器上实现此功能,您必须为 User 和 Poll 上的连接字段(即上例中的 '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
}
})
}
}
})
});
您必须在反向投票类型中执行类似的操作。要将对象添加到连接,您需要做的就是创建一个指向正确用户和 Post 的投票对象。 db.getVotesForUser() 方法应该足够聪明,可以意识到这是一个一对多连接,然后可以提取正确的对象。
创建处理连接的标准方式可能是一项艰巨的任务,但幸运的是,有一些服务可以帮助您开始使用 GraphQL,而无需自己实现所有后端逻辑。我为一项这样的服务工作 https://scaphold.io,如果您有兴趣,我很乐意与您进一步讨论这个解决方案!
使用单独的 Vote
实体建模可能更好,如 , however, to address the more general question of "how do I define additional fields on an edge?", note that you can pass edgeFields
into the connectionDefinitions
function in the graphql-relay module 中所述。
有个例子in the test suite:
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
}
}),
});
我将首先介绍我的应用程序:简单的投票应用程序,用户可以在其中创建民意调查并进行投票。简单。
目前我的 graphql 模式由用户类型、投票类型和投票类型组成,其中用户和投票与其投票具有一对多关系,使用中继连接。
投票类型包含对其选民和民意调查的引用、时间戳和实际投票值。
现在,据我了解,在规则 graphql 列表上使用连接的优势之一是能够在边缘存储数据(除了分页等...)。 我该怎么做?
如果确实可行,我的计划是摆脱投票类型,直接通过连接连接用户和他投票的民意调查,并将投票值及其时间戳存储在连接边上。
如果重要的话,选民和他的民意调查之间的连接应该是双向的,即每个用户都连接到他投票的民意调查,每个民意调查都连接到它的选民。
听起来您离想要的东西真的很近了。我认为使用 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
}
}
}
}
在此示例中,您的投票类型是沿边存储信息的实体。 Connections 优于 Lists 的一个优势是你可以沿边缘存储信息,这是正确的,但我想说更大的好处是能够对大型对象集进行分页。
要在服务器上实现此功能,您必须为 User 和 Poll 上的连接字段(即上例中的 '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
}
})
}
}
})
});
您必须在反向投票类型中执行类似的操作。要将对象添加到连接,您需要做的就是创建一个指向正确用户和 Post 的投票对象。 db.getVotesForUser() 方法应该足够聪明,可以意识到这是一个一对多连接,然后可以提取正确的对象。
创建处理连接的标准方式可能是一项艰巨的任务,但幸运的是,有一些服务可以帮助您开始使用 GraphQL,而无需自己实现所有后端逻辑。我为一项这样的服务工作 https://scaphold.io,如果您有兴趣,我很乐意与您进一步讨论这个解决方案!
使用单独的 Vote
实体建模可能更好,如 edgeFields
into the connectionDefinitions
function in the graphql-relay module 中所述。
有个例子in the test suite:
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
}
}),
});