2017-08-21 11 views
0

私は、同様の変異を実行したときに何が返されるのか奇妙な点に遭遇しました。私はちょうどこのスタックを学んで、私はmongooseと私のデータベース層としてmongodbを実装します。Graphql Apollo React:nullを返すことはできません。

私は2つの単純な突然変異を持っています。ユーザーを作成し、それをデータベースの別名レジスタに追加します。もう一方は最初のユーザーオブジェクトが作成された後に明らかにプロフィール写真を追加します。

両方のリゾルバは完全なユーザオブジェクトを返すので、ui、storeなどの更新にはいいです。サブスクリプションの実装を計画していますので、新しいデータを取得することが重要です。

私はgraphiqlを使って作業していて、奇妙な問題に遭遇しました。イメージのURLがdbに保存されていても、私の更新リゾルバはnullを返していました。レジスタリゾルバはすべてのユーザフィールドを返していました。

リゾルバの戻りオブジェクトをコンソールにログ記録すると、両方の関数が完全なユーザーオブジェクトを返していました。

私が返すオブジェクトをnullにできないようにしようとすると、エラーが返されます。

私のリゾルバは、最初にfindOneAndUpdateをコールバックで使用していましたが、実際にはユーザオブジェクトを返していました。はい、私はまだヌルになっていました。奇妙な。

代わりに私のリゾルバを手作業で変更しました。私はfindOneでユーザIDを渡して既存のユーザを検索し、次に明示的にuser.profilePic = "url of pic"とユーザオブジェクト全体の呼び出しを保存し、ユーザオブジェクトをそのコールバックに戻して返信します。ブーム、それは動作します!

この原因は何ですか?私はこれがコールバックを待たずに何らかの形でタイミングと関係があるという初期の気持ちを持っています....なぜ私の最初のアプローチがうまくいかず、私の2番目のことが分かりません。私はタイミングの深い理解を持つ誰かのためにコードを添付したり、おそらく非同期関数がチャイムインすることができます。おそらく私のスタイルをコールバックから約束または非同期待ちに更新する必要があります。

//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ヶ月のコーディング経験を持つ人のために...

答えて

2

コールバックを含めると、ドキュメントの内容にかかわらず、findOneAndUpdateは未定義を返します。一方、findOneはQueryオブジェクトを返します。ここで問題となるのは、コールバックを渡すときです。その目的は、コールバックに渡された値を引数として扱い、コールの戻り値が何であっても処理しないことです。

GraphQLを使用すると、リゾルバは値またはその値に解決されるPromiseを返すことができます。 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!! 
    }) 

最後に、あなたが約束とは異なり、その内部のreturn文は、(少なくともこの場合)何もしない、ということに注意して、コールバックを使用して終了しなければ。それらは非同期であるため、元の呼び出しで呼び出された値を何らかの方法で元の呼び出しに戻すことはできません(Promise内のすべてをラップすることなく、すでにPromiseを返すことができればそれほど価値のないパスです)。

+0

あなたは正しいです、私は元のfindOneユーザオブジェクトを返していたことに気付きました.Graphicsが正しい最新のデータを表示していましたが。私はこのパターンもエラーのために好きです、それは私がそれをやっていた方法が退屈になります。私はこのスタックの標準的なパターンを見つけるのは難しいと感じました。非常に有用なアドバイス。 – benjaminadk

+0

@benjaminadk [これはGraphQLの例の一覧です](https://github.com/chentsulin/awesome-graphql)。あなたが参考になるかもしれないマングースを使用するカップルがあります。 –

関連する問題