【问题标题】:GraphQL mutation that accepts an array of dynamic size and common scalar types in one request在一个请求中接受一组动态大小和常见标量类型的 GraphQL 突变
【发布时间】: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 方式是什么?我知道我可以通过多个突变/请求来实现结果,但我想一次性完成。

【问题讨论】:

  • 在具有namefavMovies 的架构上定义一个input type。让addUser() 将该类型的实例作为其参数。 AFAIK,列表字段对输入类型有效。
  • 是的,我必须试一试,不过我一直在寻找更好的例子
  • 在 Javascript 中,您可以像这样转换 json 数组以满足此模式:favMovies: ${JSON.stringify(moviesArray).replace(/"([^(")"]+)":/g,"$1:")}

标签: javascript graphql apollostack


【解决方案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" }] -- 这会引发错误
        猜你喜欢
        • 2019-02-07
        • 2019-11-04
        • 2019-02-17
        • 2019-11-07
        • 2017-10-28
        • 1970-01-01
        • 1970-01-01
        • 2020-10-14
        • 2022-08-03
        相关资源
        最近更新 更多