Graphql Apollo React:对于不可空的,不能 Return null

Graphql Apollo React: Can't Return null for non nullable

我发现当我 运行 类似突变时得到 return 的东西很奇怪。我只是在学习这个堆栈,我用 mongoose 作为我的数据库层实现 mongodb。

我有两个简单的突变。一个创建一个用户并将其添加到数据库中,也就是注册。另一个显然是在创建初始用户对象后添加个人资料照片。

两个解析器 return 完整的用户对象,这对更新 ui、商店等非常有用,我正计划实施订阅,所以重要的是我得到新的数据返回。

我正在用 graphiql 和 运行 解决一个奇怪的问题。我的更新解析器 returning null 即使图像 url 被保存到数据库。注册解析器 returning 所有用户字段。

在控制台记录解析器中的 return 对象后,两个函数都是 returning 一个完整的用户对象。

当我尝试使 return 对象不可为空时,我会收到错误 cant return null for non nullable for the update resolver。

我的解析器最初使用 findOneAndUpdate 和回调,实际上 return 用户对象。是的,我仍然是空的。奇怪。

我将我的解析器更改为更手动的方法。我使用传入用户 ID 的 findOne 查找现有用户,然后明确地说 user.profilePic = "url of pic" 并调用保存整个用户对象,并在回调中 returning 用户对象到那个。繁荣,成功了!

这是什么原因造成的?我最初的感觉是这与时间有关,也就是不等待回调……我真的不明白为什么我的第一种方法不起作用而第二种方法起作用。我会附上两者的代码,也许对时间有更深入了解的人或者异步函数可以插话。也许我需要将我的风格从回调更新为承诺或异步等待。

//this one doesnt work    
addProfilePic: (root, { input }, context) => {
  let update = { profilePic: input.profilePic };
  let query = { id: input.id };
  let options = { new: true, upsert: true};
  let callback = ((err, user) => {
    if(err) console.log(err.message);
    return user;
  })
  return updatedUser = User.findOneAndUpdate(query, update, options, callback)
}                    

//this one works, but returns old user object to client...
//so really, no, it doesn't work
addProfilePic: (root, { input }, context) => {
  return User.findOne({id: input.id}, ((err,user) => {
    if(err)console.log(err);
    if(user){
      user.profilePic = input.profilePic;
      user.save((err) => {
        if(err)console.log(err);
        console.log(user);
        return user;
      })
    }
  })
})

注意:传入上下文,当我实际实现时,我将从上下文中获取 ID,其中包含用户登录时的 ID。 注意:这些很快就会成为很酷的工具,但还有很多东西需要学习,尤其是对于那些拥有 3 个月总编码经验的人……即我……

不管文档怎么说,当你包含一个回调时,findOneAndUpdatereturn是未定义的。另一方面,findOne return 是一个查询对象。这里的问题是当您传递回调时,目的是让您处理作为参数传递给回调的值,而不是处理调用的 return 值是什么。

借助 GraphQL,解析器可以 return 一个值或解析为该值的 Promise。由 findOne 编辑的查询对象 return 不是 Promise,而是 "thenable",因此从某种意义上说,您是 "getting away" 以这种方式做事。但是,我怀疑如果您查看 GraphQL 实际 return 编辑的内容,您会发现它 return 原始用户对象,而不是已保存的用户对象。

如您所料,还有更好的方法:)

要获得 mongoose 到 return 的承诺,您需要:

  1. 完全放弃回调
  2. .exec() 附加到通话结尾

现在您的解析器如下所示:

addProfilePic: (root, { input }, context) => {
  let update = { profilePic: input.profilePic };
  let query = { id: input.id };
  let options = { new: true, upsert: true};
  return User.findOneAndUpdate(query, update, options).exec()
}

一些额外的注意事项可以帮助您走上正确的道路:

你会注意到我在上面的代码中没有做任何错误处理。这是因为 GraphQL 实际上会为您捕获这些错误并将它们包含在响应中。但是,如果您想提供额外的错误信息, 混淆正在 returned 给客户端的详细信息,您可以附加catch() 到你的电话,修改你里面的错误,然后把它扔回去。

既然你已经return承诺了,你可以使用then() 如果你需要要使用查询结果,请记住 return 里面的值!

return User.findOneAndUpdate(query, update, options).exec()
  .then(user => {
    console.log(user)
    // you could modify the object being handed to GraphQL here
    return user // IF you use a then, make sure you return the value!!
  })

最后,如果您最终使用回调,请注意,与 Promises 不同,其中的 return 语句不会执行任何操作(至少在本例中不会)。因为它们是异步的,所以你无法以某种方式 return 将它们调用的值返回到你的原始调用(并非没有将所有内容包装在 Promise 中,如果你已经有一个答应 returned).