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

GraphQL关联查询无法返回用户数据,报非空字段null错误

解决Cannot return null for non-nullable field User.email的问题

我帮你排查了代码,问题主要出在Mongoose模型定义不匹配和事件创建时未正确关联用户这两个地方,具体如下:

1. 核心问题:事件模型的creator字段类型错误

你的event.js里把creator定义成了数组类型:

creator: [ { type: Schema.Types.ObjectId, ref: 'User' } ]

但在GraphQL的Event类型里,creator被声明为单个User!(非空的单个用户)。当你用populate('creator')查询时,得到的是一个用户数组,而不是单个用户对象。这就导致GraphQL尝试从数组中读取email字段时失败,返回null,违反了User.email的非空约束,触发了错误。

2. 修复步骤

步骤1:修正Event模型的creator字段

打开event.js,把creator改成单个ObjectId类型(因为一个事件应该只有一个创建者):

const eventSchema = new Schema({
  title: { type: String, required: true },
  description: { type: String, required: true },
  price: { type: Number, required: true },
  date: { type: Date, required: true },
  // 去掉数组括号,改成单个关联
  creator: { type: Schema.Types.ObjectId, ref: 'User', required: true }
});

步骤2:完善createEvent的Mutation逻辑

你当前的rootValue里缺少createEvent的实现,而且即使有,也没有把事件和用户关联起来。补充如下代码(注意:实际项目中你需要通过身份验证获取当前用户ID,这里先以测试为例):

rootValue: {
  events: () => {
    return Event.find()
      .populate('creator')
      .then(events => {
        return events.map(event => {
          // 现在creator是单个用户对象,解构后能正确获取email
          return { ...event._doc, _id: event.id };
        });
      })
      .catch(err => { throw err; });
  },
  createEvent: async (args) => {
    // 1. 先找到一个已存在的用户(实际项目中应该从请求上下文获取登录用户)
    const existingUser = await User.findOne({ email: "test@example.com" });
    if (!existingUser) {
      throw new Error("用户不存在,请先创建用户!");
    }

    // 2. 创建事件并关联用户ID
    const event = new Event({
      title: args.eventInput.title,
      description: args.eventInput.description,
      price: parseFloat(args.eventInput.price),
      date: new Date(args.eventInput.date),
      creator: existingUser._id // 关联创建者的用户ID
    });

    // 3. 保存事件并更新用户的createdEvents列表
    const savedEvent = await event.save();
    existingUser.createdEvents.push(savedEvent._id);
    await existingUser.save();

    // 4. 返回事件数据,同时确保creator字段正确关联
    return { ...savedEvent._doc, _id: savedEvent.id, creator: existingUser };
  },
  createUser: async (args) => {
    // 补充你的createUser逻辑(注意密码要加密)
    const hashedPassword = await bcrypt.hash(args.userInput.password, 12);
    const user = new User({
      email: args.userInput.email,
      password: hashedPassword
    });
    return user.save()
      .then(result => {
        // 注意:不要返回明文密码,这里可以把password设为null或者不返回
        return { ...result._doc, _id: result.id, password: null };
      })
      .catch(err => { throw err; });
  }
}

步骤3:优化User类型的GraphQL定义(可选但重要)

你的User类型里返回password字段是不安全的,建议把它改成非必填或者直接移除:

type User {
  _id: ID!
  email: String!
  # 移除password,或者改成password: String
  createdEvents: [Event!]
}

3. 测试验证

  1. 先通过GraphiQL执行createUser mutation创建一个用户:
mutation {
  createUser(userInput: { email: "test@example.com", password: "123456" }) {
    _id
    email
  }
}
  1. 再执行createEvent mutation创建一个关联该用户的事件:
mutation {
  createEvent(eventInput: {
    title: "Test Event",
    description: "A test event",
    price: 99.99,
    date: "2024-12-31T23:59:59Z"
  }) {
    _id
    title
    creator {
      email
    }
  }
}
  1. 最后执行你的查询:
query {
  events {
    creator {
      email
    }
  }
}

这时候应该能正确返回用户的email,不会再出现null错误了。

内容的提问来源于stack exchange,提问作者pl-jay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:22:01