2016-10-12 4 views
1

私はMongoDBの(およびそのDOTNETコアC#のドライバ)に新たなんだ、と私はIAsyncCursorの挙動について、次の質問があります。公式ドキュメントからMongoDB C#ドライバIAsyncCursor <BsonDocument>の動作ですか?

https://docs.mongodb.com/getting-started/csharp/query/は、それが思わIAsyncCursorを反復処理の推奨される方法次のとおりです。

var collection = _database.GetCollection<BsonDocument>("restaurants"); 
var filter = new BsonDocument(); 
var count = 0; 
using (var cursor = await collection.FindAsync(filter)) 
{ 
    while (await cursor.MoveNextAsync()) 
    { 
     var batch = cursor.Current; 
     foreach (var document in batch) 
     { 
      // process document 
      count++; 
     } 
    } 
} 

しかし、それは「MoveNextAsync」最初のwhileループ、返された文書の「現在」のバッチを取得することを思わ、「MoveNextAsyncは」「現在」のバッチをスキップしていますか?論理的には、次の変更されたコードスニペットが意味がありますか?

var collection = _database.GetCollection<BsonDocument>("restaurants"); 
var filter = new BsonDocument(); 
var count = 0; 
using (var cursor = await collection.FindAsync(filter)) 
{ 
    do 
    { 
     if (cursor.Current != null) 
     { 
      var batch = cursor.Current; 
      foreach (var document in batch) 
      { 
       // process document 
       count++; 
      } 
     } 
    } 
    while (await cursor.MoveNextAsync()) 
} 

私の理解では、カーソルが(もしあれば)、既に「現在」のバッチを指すことから始めなければならない、と私は最初に「現在」のバッチが何であれで作業し、次のバッチに移動しなければならないということですもしあれば、文書の

しかし、私はオンラインで見つけることができるすべてのソースについて、常に「MoveNext」を実行してからバッチを処理するように見える - これはFindAsyncによって返されたIAsyncCursorが位置1文書の実際の「現在」(または第1の)バッチよりも前に、「MoveNext」が最初に呼び出されてカーソルを実際の電流を指すように移動させる必要があります。

"MoveNext"を呼び出すと、まずwhileループがより一貫しているため、自分自身のコードスニペットで(現在の) "body"の内部の "現在"の妥当性をチェックする必要はありません。行う"。 "First()"メソッドが実際に "MoveNext"を内部的に実行して、最初に返された最初のドキュメントを返すようになりました。 「現在の」バッチの文書。

また、 "FindAsync"を使用していて、ドキュメントが自分のフィルタに基づいて見つからない場合、返されたIAsyncCursor "null"または "MoveNext"はfalseを返しますか? FindAsyncから返されるIAsyncCursorは常に有効なオブジェクトなので、nullを過度に確認する必要はなく、MoveNext()またはFirst()の戻り値を確認するだけで済みます。

MongoDBの専門家があなたの洞察を得てくれますか?

ありがとうございます!

答えて

1

オンラインで見つかったすべてのテストとソースから、FindAsyncメソッドから返されたIAsyncCursorが最初はニュートラル状態(「現在」はnullと思われる)で開始されていたことがわかりました。そのMoveNext(Async)は、最初のバッチに移動するために最初に呼び出されなければなりません。 "Current"はドキュメントの最初のバッチを含んでいます - 私も存在しないfind結果を観察しました。MoveNextはカーソルに "現在の "ではありませんが、Current.Count()は0を返します。つまり、MoveNextは成功したにもかかわらず、このバッチにはドキュメントがありません。これは何らかの形でAPIデザインの一貫性に関する問題を公開します。ドキュメントがなくなったことを示すfalseを返すか、成功した "MoveNext"の後に "Current"をnullにして"Current"がnullでない場合、Current.Count()== 0はドキュメントがないことを示します。今では、私のコードが安全であることを確認するために3つの条件をすべてチェックしていますが、私は "MoveNext"を既にfalseに戻して、それ以上のドキュメントが使用する最も直感的なAPIではないと考えています。

1

最初のコードサンプルは正しく、最初のバッチをスキップしません。ただし、バッチを明示的に制御したい場合は、MoveNextAsyncを直接使用する必要があります。

そうでない場合、それはあなたのためにその複雑さをラップForEachAsyncを使用するように簡単です:

using (var cursor = await collection.FindAsync(filter)) 
{ 
    await cursor.ForEachAsync(document => 
    { 
     // process document 
     count++; 
    } 
} 

ForEachAsyncソースhereを参照してください。

ソースに表示されているように、ForEachAsyncはカーソルの所有権を取り消して処理しますので、ご自分のusingを省略することもできます。

+0

答えをいただきありがとうございます。私は大部分ForEachAsyncを認識しており、使用しています。しかし、私の質問はMoveNextの動作に関するものですが、ForEachAsyncを使用して、サンプルコードのバニラwhileループを置き換えるかどうかは厳密には判断できません。または、私の質問がより正確に心配しているMoveNextの動作について、より具体的になるかもしれませんか? – Dejavu

+0

@DejavuあなたはMongoDBとドライバを初めて使ったので、必要以上に難しいものになっていると思っていました。 – JohnnyHK

関連する問題