在一个请求中接受一组动态大小和常见标量类型的 GraphQL 突变
Posted
技术标签:
【中文标题】在一个请求中接受一组动态大小和常见标量类型的 GraphQL 突变【英文标题】:GraphQL mutation that accepts an array of dynamic size and common scalar types in one request 【发布时间】:2017-04-03 12:22:33 【问题描述】:我需要能够在单个请求中创建一个用户并添加它最喜欢的电影(一组对象,其中引用了 Movies 集合和他对每部电影的个人评分)。
可能看起来像这样的东西(伪代码)
var exSchema = `
type Mutation
addUser(
name: String!
favMovies: [ movie: String! #ref to movies coll
personal_rating: Int! # this is different for every movie
]
) : User
...
`
在单个请求中执行此操作的 graphql 方式是什么?我知道我可以通过多个突变/请求来实现结果,但我想一次性完成。
【问题讨论】:
在具有name
和favMovies
的架构上定义一个input type。让addUser()
将该类型的实例作为其参数。 AFAIK,列表字段对输入类型有效。
是的,我必须试一试,不过我一直在寻找更好的例子
在 javascript 中,您可以像这样转换 json 数组以满足此模式:favMovies: $JSON.stringify(moviesArray).replace(/"([^(")"]+)":/g,"$1:")
【参考方案1】:
对于那些不需要为一个请求传递数组并且愿意为每个突变发出请求的想法的人。 (我用的是Vue3,compisition Api,但是React和Angular开发者还是可以理解的)。
你不能这样循环突变:
function createProject()
for (let i = 0; i < state.arrOfItems.length; i++)
const mutate: addImplementation = useMutation(
post_dataToServer,
() => (
variables:
implementation_type_id: state.arrOfItems[i],
sow_id: state.newSowId,
,
)
);
addImplementation();
这会给你一个错误,因为突变必须在 setup() 中。 (这是您将收到的错误:https://github.com/vuejs/vue-apollo/issues/888)
而是创建一个子组件,并将数组映射到父组件中。
在 Parent.vue 中
<div v-for="(card, id) in state.arrOfItems">
<ChildComponent
:id="id"
:card="card"
/>
</div>
在 ChildComponent.vue 中
收到道具并:
const mutate: addImplementation = useMutation(
post_dataToServer,
() => (
variables:
implementation_id: props.arrOfItems,
id: props.id,
,
)
);
【讨论】:
【参考方案2】:我对您的要求的理解是,如果您有以下代码
const user =
name:"Rohit",
age:27,
marks: [10,15],
subjects:[
name:"maths",
name:"science"
]
;
const query = `mutation
createUser(user:$user)
name
`
你一定会得到类似的东西
"mutation
createUser(user:[object Object])
name
"
而不是预期的
"mutation
createUser(user:
name: "Rohit" ,
age: 27 ,
marks: [10 ,15 ] ,
subjects: [
name: "maths" ,
name: "science"
]
)
name
"
如果这是您想要实现的,那么gqlast 是一个不错的标签功能,您可以使用它来获得预期的结果
只需从here 中获取 js 文件并将其用作:
const user =
name:"Rohit",
age:27,
marks: [10,15],
subjects:[
name:"maths",
name:"science"
]
;
const query = gqlast`mutation
createUser(user:$user)
name
`
存储在变量query
中的结果将是:
"mutation
createUser(user:
name: "Rohit" ,
age: 27 ,
marks: [10 ,15 ] ,
subjects: [
name: "maths" ,
name: "science"
]
)
name
"
【讨论】:
【参考方案3】:我想出了这个简单的解决方案 - 不使用 JSON。仅使用一个输入。希望它会帮助别人。
我必须添加到这种类型:
type Option
id: ID!
status: String!
products: [Product!]!
我们可以添加突变类型并添加输入如下:
type Mutation
createOption(data: [createProductInput!]!): Option!
// other mutation definitions
input createProductInput
id: ID!
name: String!
price: Float!
producer: ID!
status: String
然后可以使用以下解析器:
const resolvers =
Mutation:
createOption(parent, args, ctx, info)
const status = args.data[0].status;
// Below code removes 'status' from all array items not to pollute DB.
// if you query for 'status' after adding option 'null' will be shown.
// But 'status': null should not be added to DB. See result of log below.
args.data.forEach((item) =>
delete item.status
);
console.log('args.data - ', args.data);
const option =
id: uuidv4(),
status: status, // or if using babel status,
products: args.data
options.push(option)
return option
,
// other mutation resolvers
现在您可以使用它来添加一个选项(STATUS 取自数组中的第一项 - 它可以为空):
mutation
createOption(data:
[
id: "prodB",
name: "componentB",
price: 20,
producer: "e4",
status: "CANCELLED"
,
id: "prodD",
name: "componentD",
price: 15,
producer: "e5"
]
)
id
status
products
name
price
生产:
"data":
"createOption":
"id": "d12ef60f-21a8-41f3-825d-5762630acdb4",
"status": "CANCELLED",
"products": [
"name": "componentB",
"price": 20,
,
"name": "componentD",
"price": 15,
]
不用说要得到以上结果,你需要添加:
type Query
products(query: String): [Product!]!
// others
type Product
id: ID!
name: String!
price: Float!
producer: Company!
status: String
我知道这不是最好的方法,但我没有在文档中找到这样做的方法。
【讨论】:
【参考方案4】:我最终手动解析了正确的架构,因为 JavaScript 数组和 JSON.stringify 字符串不被接受为 graphQL 架构格式。
const id = 5;
const title = 'Title test';
let formattedAttachments = '';
attachments.map(attachment =>
formattedAttachments += ` id: $attachment.id, short_id: "$attachment.shortid" `;
// id: 1, short_id: "abcxyz" id: 2, short_id: "bcdqrs"
);
// Query
const query = `
mutation
addChallengeReply(
challengeId: $id,
title: "$title",
attachments: [$formattedAttachments]
)
id
title
description
`;
【讨论】:
这拯救了我的一天。非常感谢sn-p【参考方案5】:你可以像这样传递一个数组
var MovieSchema = `
type Movie
name: String
input MovieInput
name: String
mutation
addMovies(movies: [MovieInput]): [Movie]
`
然后在你的突变中,你可以传递一个数组,如
mutation
addMovies(movies: [name: 'name1', name: 'name2'])
name
没有测试过代码,但你明白了
【讨论】:
这太酷了,但是当我将movies: String
更改为 movies: [MovieInput]
时,graphql 会抛出 Error: Expected Input type. 当然在此之前我已经声明了 Type MovieInput
@octohedron 非常感谢!我一直在努力解决这个问题。
@EdmondTamas 注意MovieInput
不是一个类型,而是一个input
;因此,如答案所示,必须有两个定义,一个用于type
,另一个用于input
- 并且名称也必须彼此不同,因为不允许使用两个具有相同名称的定义。 【参考方案6】:
将它们作为 JSON 字符串传递。我就是这么做的。
【讨论】:
@Gazta 我有同样的问题,你有没有办法将 JSON 数组作为字符串传递?你是怎么逃出来的? @EdmondTamas 添加了解决方案 JSON.stringify 也解析了密钥: addMovies(movies: [ "name": "name1" ] -- 这会引发错误以上是关于在一个请求中接受一组动态大小和常见标量类型的 GraphQL 突变的主要内容,如果未能解决你的问题,请参考以下文章