Graphql Apollo React: Can't return null for non null



我在运行类似突变时遇到过一个奇怪的结果。 我只是在学习这个堆栈,我用猫鼬作为我的数据库层实现MongoDB。

我有两个简单的突变。 一个创建一个用户并将其添加到数据库(又名寄存器(中。 另一个显然是在创建初始用户对象后添加配置文件图片。

两个解析器都返回完整的用户对象,这对于更新 UI、存储等很好,我计划实施订阅,因此取回新数据很重要。

我正在使用 Graphiql 解决问题,遇到了一个奇怪的问题。 即使图像 URL 已保存到数据库,我的更新解析程序仍返回 null。 寄存器解析器返回所有用户字段。

在控制台记录解析程序中的返回对象时,两个函数都返回完整的用户对象。

当我尝试使返回对象不可为空时,我会收到错误无法为更新解析程序返回不可空的空。

我的解析器最初使用 findOneAndUpdate 和一个回调,该回调实际上确实返回了用户对象。 是的,我仍然得到空。奇怪。

我将解析器更改为更手动的方法。 我使用 findOne 查找现有用户,传入用户 ID,然后明确表示 user.profilePic = "pic 的网址"和整个用户对象的调用保存,并在回调中返回用户对象。 轰,这行得通!

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

//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,其中包含用户登录时的用户。 注意:这些很快就会成为很酷的工具,但需要学习很多东西,特别是对于总编码经验为 3 个月的人来说......即我...

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

使用 GraphQL,解析器可以返回解析为该值的值或承诺。findOne返回的 Query 对象不是 Promise,而是"可"的",因此从某种意义上说,您以这种方式"逃脱"了。但是,我怀疑如果您查看 GraphQL 实际返回的内容,您会发现它返回的是原始用户对象,而不是保存的对象。

正如你所猜想的,有一个更好的方法:)

要让mongoose返回承诺,您需要:

  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 实际上会为您捕获这些错误并将它们包含在响应中。但是,如果要提供其他错误信息,模糊处理返回给客户端的详细信息,则可以将catch()附加到调用中,修改其中的错误,然后将其扔回去。

现在你正在返回一个承诺,如果你需要使用查询结果,你可以使用then(),只要记住返回里面的值!

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!!
})

最后,如果你最终使用了回调,请注意,与 Promise 不同,它们中的 return 语句不会做任何事情(至少在这种情况下不会(。因为它们是异步的,所以你不可能以某种方式将调用它们的值返回到你的源调用(不是没有将所有内容包装在一个 Promise 中,如果你已经可以返回一个 Promise,这是一条不值得走的路径(。

最新更新