GraphQL - 返回依赖于参数的计算类型

时间:2017-11-16 13:50:14

标签: mysql node.js schema graphql reducers

概述(简化):

在我的NodeJS服务器中,我实现了以下GraphQL架构:

type Item {
  name: String,
  value: Float
}


type Query {
  items(names: [String]!): [Item]
}

客户端查询然后传递一个名称数组作为参数:

{
  items(names: ["total","active"] ) {
    name
    value
  }
}

后端API查询mysql数据库,查看“总计”和“活动”字段(我的数据库表上的列)并减少响应,如下所示:< / p>

[{"name":"total" , value:100} , {"name":"active" , value:50}]

我希望我的graphQL API支持“ratio”Item,I.E:我想发送以下查询:

{
  items(names: ["ratio"] ) {
    name
    value
  }
}

{
  items(names: ["total","active","ratio"] ) {
    name
    value
  }
}

并返回有效/总计作为该新字段([{"name":"ratio" , value:0.5}])的计算结果。以不同方式处理“比率”字段的通用方法是什么?

它应该是我的架构中的新类型还是应该在reducer中实现逻辑?

2 个答案:

答案 0 :(得分:2)

您可以设置解析器功能,以便它使用第二个参数 - 参数 - 来查看名称“ratio”是否在您的names数组中:

resolve: (root, { names }, context, fieldASTs) => {
    let arrayOfItems;
    // Contact DB, populate arrayOfItems with your total / active items

    // if 'ratio' is within your name array argument, calculate it:
    if (names.indexOf("ratio") > -1){
        // Calculate ratio
        arrayOfItems.push({ name: "ratio", value: calculatedRatio });
    }

    return(arrayOfItems);
}

我希望我能正确理解你的问题

答案 1 :(得分:2)

Joe的回答(在从数据库中获取结果后将{"name":"ratio" , value:data.active/data.total}附加到结果中)可以在不进行任何架构更改的情况下执行此操作。

作为替代方法或在GraphQL中更优雅的方式,可以在类型本身中指定字段名称,而不是将它们作为参数传递。并通过编写解析器来计算ratio

因此,GraphQL架构将是:

Item {
  total: Int,
  active: Int,
  ratio: Float
}

type Query {
  items: [Item]
}

客户指定字段:

{
  items {
    total 
    active 
    ratio
  }
}

可以在解析器内计算ratio

以下是代码:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { graphql } = require('graphql');
const { makeExecutableSchema } = require('graphql-tools');
const getFieldNames = require('graphql-list-fields');

const typeDefs = `
type Item {
  total: Int,
  active: Int,
  ratio: Float
}

type Query {
  items: [Item]
}
`;

const resolvers = {
  Query: {
    items(obj, args, context, info) {
      const fields = getFieldNames(info) // get the array of field names specified by the client
      return context.db.getItems(fields)
    }
  },
  Item: {
    ratio: (obj) => obj.active / obj.total // resolver for finding ratio
  }
};

const schema = makeExecutableSchema({ typeDefs, resolvers });

const db = {
  getItems: (fields) => // table.select(fields)
    [{total: 10, active: 5},{total: 5, active: 5},{total: 15, active: 5}] // dummy data
}
graphql(
  schema, 
  `query{
    items{
      total,
      active,
      ratio
    }
  }`, 
  {}, // rootValue
  { db } // context
).then(data => console.log(JSON.stringify(data)))