Мутация GraphQL, которая принимает массив динамического размера и общие скалярные типы в одном запросе
Мне нужно иметь возможность создать пользователя и добавить его любимые фильмы (массив объектов со ссылкой на коллекцию фильмов и его личный рейтинг для каждого фильма) в одном запросе.
Нечто похожее на это (псевдокод)
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 способ сделать это в одном запросе? Я знаю, что могу достичь результата с помощью нескольких мутаций / запросов, но я бы хотел сделать это за один раз.
6 ответов
Вы можете передать массив, как это
var MovieSchema = `
type Movie {
name: String
}
input MovieInput {
name: String
}
mutation {
addMovies(movies: [MovieInput]): [Movie]
}
`
Затем в вашей мутации, вы можете передать массив как
mutation {
addMovies(movies: [{name: 'name1'}, {name: 'name2'}]) {
name
}
}
Не проверял код, но вы поняли идею
Я придумал это простое решение - НЕТ 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
}
Я знаю, что это не лучший способ, но я не нашел способа сделать это в документации.
В итоге я вручную проанализировал правильную схему, поскольку массивы 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
}
}
`;
Что я понимаю под вашим требованием, так это то, что если у вас есть следующий код
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 - хорошая функция тега, которую вы можете использовать для получения ожидаемого результата.
Просто возьмите отсюда файл 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
}
}"
Для тех из вас, кому не нужно передавать массив для одного запроса, и кто открыт для идеи делать запрос для каждой мутации. (Я использую Vue3, сборку 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,
},
})
);