Graphql Apollo React:不能为非可空返回null

时间:2017-08-21 00:04:57

标签: mongodb mongoose graphql graphql-js

当我运行类似的突变时,我遇到了一些奇怪的东西。我正在学习这个堆栈,我用mongoose实现mongodb作为我的数据库层。

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

两个解析器都返回完整的用户对象,这对于更新ui,store等很有帮助,我正在计划实现订阅,因此重新获取新数据非常重要。

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

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

当我试图使返回对象不可为空时,我会得到错误,但不能为更新解析器的非可空值返回null。

我的解析器最初使用的是带有回调的findOneAndUpdate,该回调确实返回了用户对象。是的,我仍然无效。怪异。

我将我的解析器更改为更加手动的方法。我通过findOne传递用户id查找现有用户,然后显式地说user.profilePic =“url of pic”和整个用户对象的调用保存,并将回调中的用户对象返回到该用户对象。和繁荣,这是有效的!

那是什么造成的呢?我最初的感觉是,这与时间某种方式有关,而不是等待回调....我真的不明白为什么我的第一种方法不起作用而我的第二种做法。我会附上代码,可能是对时间有更深入理解的人,也可能是异步函数可以插入。也许我需要将我的风格从回调更新为promises或async等待。

//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个月的人...即我...

1 个答案:

答案 0 :(得分:2)

尽管文档说的是,当你包含一个回调时,findOneAndUpdate返回undefined。另一方面,findOne返回Query对象。这里的问题是当你传递一个回调时,你的目的就是把你传递给回调的值作为参数处理,而不是处理调用的返回值。

使用GraphQL,解析器可以返回一个值或一个解析为该值的Promise。 findOne返回的Query对象不是Promise,但是" thenable"所以从某种意义上说,你已经离开了#34;以这种方式做事。但是,我怀疑如果您查看GraphQL实际返回的内容,您会发现它返回的是原始用户对象,而不是已保存的用户对象。

正如您猜测的那样,有更好的方法:)

要让mongoose返回Promise,您需要:

  1. 完全放弃回调
  2. 在通话结束时附加.exec()
  3. 现在你的解析器看起来像这样:

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

    最后,如果你最终使用回调,请注意,与Promises不同,其中的return语句不做任何事情(至少在这种情况下不做)。因为它们是异步的,所以你无法以某种方式将它们被调用的值返回到你的原始调用(不是没有将所有内容都包含在Promise中,并且这条路径并不值得。如果你已经退回了承诺,请服用。)