Mongodb 阿波罗反应图:Can';对于不可为null的对象,t返回null

Mongodb 阿波罗反应图:Can';对于不可为null的对象,t返回null,mongodb,mongoose,graphql,graphql-js,Mongodb,Mongoose,Graphql,Graphql Js,我遇到了一个奇怪的现象,当我运行类似的突变时,返回的是什么。我正在学习这个堆栈,我用mongoose作为我的数据库层来实现mongodb 我有两个简单的突变。创建一个用户并将其添加到数据库或注册表中。另一个在创建初始用户对象之后添加一个概要文件pic 两个解析器都返回完整的用户对象,这对于更新ui、存储等很好,我正计划实现订阅,因此重要的是我要返回新数据 我在用graphiql解决问题时遇到了一个奇怪的问题。即使图像url被保存到数据库中,我的更新解析程序仍返回null。寄存器解析程序正在返回所

我遇到了一个奇怪的现象,当我运行类似的突变时,返回的是什么。我正在学习这个堆栈,我用mongoose作为我的数据库层来实现mongodb

我有两个简单的突变。创建一个用户并将其添加到数据库或注册表中。另一个在创建初始用户对象之后添加一个概要文件pic

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

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

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

当我试图使返回对象不可为null时,我会得到一个错误:更新解析程序不能为不可为null返回null

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

我将解析器改为更手动的方法。我使用findOne查找现有用户,传入用户id,然后显式地说user.profilePic=“url of pic”,并调用整个用户对象的save,然后在回调中将用户对象返回给该用户对象。砰的一声,那就行了

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

//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个月总编码经验的人来说,比如我…

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

使用GraphQL,解析程序可以返回解析为该值的值或承诺。
findOne
返回的查询对象不是承诺,而是“thenable”,因此从某种意义上讲,您可以通过这种方式“逃脱”。但是,我怀疑如果您查看GraphQL实际返回的内容,您会发现它返回的是原始用户对象,而不是保存的对象

正如您所猜测的,有一种更好的方法:)

要让猫鼬返回承诺,您需要:

  • 完全放弃回调
  • .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!!
      })
    

    最后,如果最终使用回调,请注意,与承诺不同,回调中的返回语句没有任何作用(至少在本例中没有)。因为它们是异步的,所以您无法以某种方式将调用它们的值返回到原始调用(不是不将所有内容包装在承诺中,如果您已经返回了承诺,那么这条路径就不值得采用)。

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

    使用GraphQL,解析程序可以返回解析为该值的值或承诺。
    findOne
    返回的查询对象不是承诺,而是“thenable”,因此从某种意义上讲,您可以通过这种方式“逃脱”。但是,我怀疑如果您查看GraphQL实际返回的内容,您会发现它返回的是原始用户对象,而不是保存的对象

    正如您所猜测的,有一种更好的方法:)

    要让猫鼬返回承诺,您需要:

  • 完全放弃回调
  • .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()