You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GraphQL添加Material类型报错:fields需为对象或返回对象的函数

问题描述

我开发了一个基于MongoDB的应用,原本Customer和Ticket相关Schema运行正常。添加Materials集合并配置Schema后,持续报错:

Error: Material fields must be an object with field names as keys or a function which returns such an object

服务器崩溃,无法访问http://localhost:5400/graphql,注释Materials相关代码后恢复正常。以下是我的Schema代码:

const Customer = require('../models/Customer');
const Ticket = require('../models/Ticket');
const Material = require('../models/Material');


const { GraphQLObjectType, 
        GraphQLString, 
        GraphQLSchema, 
        GraphQLID, 
        GraphQLList, 
        GraphQLInt, 
        GraphQLNonNull,
        GraphQLDeprecatedDirective,
      } = require('graphql');

//Tickets
const TicketType = new GraphQLObjectType({
  name: 'Ticket',
  fields: () => ({
    id: { type: GraphQLID },
    date: { type: GraphQLString},
    ticketNum: { type: GraphQLString},
    customer: { 
      type: CustomerType,
      resolve(parent, args) {
        return Customer.findById(parent.customerId);
      },
    },
    material: { type: GraphQLString},
    tareWeight: { type: GraphQLInt},
    grossWeight: { type: GraphQLInt},
    netWeight: { type: GraphQLInt},
    notes: { type: GraphQLString},
  }),
});

//Materials
const MaterialType = new GraphQLObjectType({
  name: "Material",
  Fields: () => ({
    id: { type: GraphQLID },
    matId: { type: GraphQLString},
    name: { type: GraphQLString },
    price: { type: GraphQLInt },
    unit: { type: GraphQLString},
    notes: { type: GraphQLString,}
  }),  
});


//Customers
const CustomerType = new GraphQLObjectType({
  name: "Customer",
  fields: () => ({
    id: { type: GraphQLID },
    custId: { type: GraphQLString}, 
    name: { type: GraphQLString}, 
    street: { type: GraphQLString}, 
    city: { type: GraphQLString}, 
    zip: { type: GraphQLString}, 
    webSite: { type: GraphQLString}, 
    email: { type: GraphQLString},
    phone: { type: GraphQLString},
  }),
});

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: {

    tickets: {
      type: new GraphQLList(TicketType),
      resolve(parent, args) {
        return Ticket.find();
      },
    },
    ticket: {
      type: TicketType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return Ticket.findById(args.id);
      },
    },

    customers: {
      type: new GraphQLList(CustomerType),
      resolve(parent, args) {
        return Customer.find();
      },
    },    
    customer: {
      type: CustomerType, 
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return Customer.findById(args.id);
      }, 
    },

    materials: {
      type: new GraphQLList(MaterialType),
      resolve(parent, args) {
        return Material.find();
      },
    },
    material: {
      type: MaterialType,
      args: {id: { type: GraphQLID } },
      resolve(parent, args) {
        return Material.findById(args.id);
      },
    },
  },
});

//Mutations
const mutation = new GraphQLObjectType({
  name: 'Mutation',
  fields: {
    //Add Customer
    addCustomer: {
      type: CustomerType,
      args: {
    custId: { type: GraphQLString}, 
    name: { type: GraphQLString}, 
    street: { type: GraphQLString}, 
    city: { type: GraphQLString}, 
    zip: { type: GraphQLString}, 
    webSite: { type: GraphQLString}, 
    email: { type: GraphQLString},
    phone: { type: GraphQLString},
      },
      resolve(parent, args) {
        const customer = new Customer({
          custId: args.custId,
          name: args.name,
          street: args.street,
          city: args.city,
          zip: args.zip,
          webSite: args.webSite,
          email: args.email,
          phone: args.phone,
        });
        return customer.save();
      }
    },
    // //Add Material
    addMaterial: {
      type: MaterialType,
      args: {
    matId: { type: GraphQLString}, 
    name: { type: GraphQLString}, 
    price: { type: GraphQLString}, 
    unit: { type: GraphQLString}, 
    notes: { type: GraphQLString},
      },
      resolve(parent, args) {
        const material = new Material({
          matId: args.matId,
          name: args.name,
          price: args.price,
          unit: args.unit,
          notes: args.notes,
        });
        return material.save();
      }
    },
    // Delete Customer
    deleteCustomer: {
      type: CustomerType,
      args: {
        id: { type: GraphQLNonNull(GraphQLID) },
      },
      resolve(parent, args) {
        return Customer.findByIdAndRemove(args.id);
      },
    },



    // Add Ticket
    addTicket: {
      type: TicketType,
      args: {
        date: { type: GraphQLNonNull(GraphQLString) },
        ticketNum: { type: GraphQLNonNull(GraphQLString) },
        customerId: { type: GraphQLNonNull(GraphQLID) },
        material: { type: GraphQLNonNull(GraphQLString) },
        tareWeight: { type: GraphQLNonNull(GraphQLInt) },
        grossWeight: { type: GraphQLNonNull(GraphQLInt) },
        netWeight: { type: GraphQLNonNull(GraphQLInt) },
        notes: { type: GraphQLNonNull(GraphQLString) },
      },
      resolve(parent, args) {
        const ticket = new Ticket({
          date: args.date,
          ticketNum: args.ticketNum,
          customerId: args.customerId,
          material: args.material,
          tareWeight: args.tareWeight,
          grossWeight: args.grossWeight,
          netWeight: args.netWeight,
          notes: args.notes,
        });
        return ticket.save();
      }
    },

    //Delete a Ticket
    deleteTicket: {
      type: TicketType,
      args: {
        id: { type: GraphQLNonNull(GraphQLID) },
      },
      resolve(parent, args) {
        return Ticket.findByIdAndRemove(args.id);
      },
    },


  // Update Ticket
  updateTicket: {
    type: TicketType,
    args: {
      id: { type: GraphQLNonNull(GraphQLID) },
      date: { type: GraphQLString },
      ticketNum: { type: GraphQLString },
      // customerId: { type: GraphQLID },
      material: { type: GraphQLString },
      tareWeight: { type: GraphQLInt },
      grossWeight: { type: GraphQLInt },
      netWeight: { type: GraphQLInt },
      notes: { type: GraphQLString },
    },
    resolve(parent, args) {
      return Ticket.findByIdAndUpdate(
        args.id,
        {
          $set: {
            date: args.date,
            ticketNum: args.ticketNum,
            // customerId: args.customerId,
            material: args.material,
            tareWeight: args.tareWeight,
            grossWeight: args.grossWeight,
            netWeight: args.netWeight,
            notes: args.notes,
          },
        },
        { new: true }
      );
    },
   },
  },
});


module.exports = new GraphQLSchema({
  query: RootQuery,
  mutation
});
错误原因

定义MaterialType时出现大小写错误:把必填属性fields写成了Fields(首字母大写)。GraphQL无法识别这个错误的属性名,会直接忽略它,导致MaterialType缺少核心的字段配置,从而抛出报错。

修复方案
  1. 修正MaterialType中的属性名,将Fields改为小写的fields,和其他类型保持一致:
//Materials
const MaterialType = new GraphQLObjectType({
  name: "Material",
  fields: () => ({ // 此处修正为小写fields
    id: { type: GraphQLID },
    matId: { type: GraphQLString},
    name: { type: GraphQLString },
    price: { type: GraphQLInt },
    unit: { type: GraphQLString},
    notes: { type: GraphQLString,}
  }),  
});
  1. 额外修正一个类型不匹配问题:addMaterial mutation中price的类型是GraphQLString,但MaterialType里price定义为GraphQLInt,统一类型避免后续数据异常:
//Add Material
addMaterial: {
  type: MaterialType,
  args: {
    matId: { type: GraphQLString}, 
    name: { type: GraphQLString}, 
    price: { type: GraphQLInt }, // 此处修正为GraphQLInt
    unit: { type: GraphQLString}, 
    notes: { type: GraphQLString},
  },
  resolve(parent, args) {
    const material = new Material({
      matId: args.matId,
      name: args.name,
      price: args.price,
      unit: args.unit,
      notes: args.notes,
    });
    return material.save();
  }
},

内容的提问来源于stack exchange,提问作者Nate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:01:20