Cursor.hasNext()
メソッドも「非同期」であるため、await
必要があります それも。 Cursor.next()
についても同じことが言えます 。したがって、実際の「ループ」の使用法は、実際にはwhile
である必要があります :
async function dbanalyze(){
let cursor = db.collection('randomcollection').find()
while ( await cursor.hasNext() ) { // will return false when there are no more results
let doc = await cursor.next(); // actually gets the document
// do something, possibly async with the current document
}
}
コメントに記載されているように、最終的にはCursor.hasNext()
false
を返します カーソルが実際に使い果たされたとき、およびCursor.next()
カーソルから各値を実際に取得しているものです。他の構造を実行してbreak
することができます hasNext()
の場合のループ false
です 、ただし、より自然にwhile
に適しています 。
これらはまだ「非同期」であるため、await
必要があります それぞれの約束の決議、そしてそれはあなたが逃した主な事実でした。
Cursor.map()
について 、それならおそらくasync
でマークできるという点を見逃しているでしょう 提供された関数にもフラグを立てます:
cursor.map( async doc => { // We can mark as async
let newDoc = await someAsyncMethod(doc); // so you can then await inside
return newDoc;
})
ただし、.pipe()
を使用して回避できない限り、実際にはどこかで「繰り返し」たいと思うでしょう。 他の出力先へ。
また、async/await
フラグはCursor.forEach()
も作成します 「またもっと実用的」 、これは一般的な欠陥の1つであるため、「内部」非同期呼び出しを単純に処理できないことでしたが、これらのフラグを使用すると、必須であるため、簡単に処理できるようになりました。 コールバックを使用します。おそらくこれをPromiseでラップする必要があります:
await new Promise((resolve, reject) =>
cursor.forEach(
async doc => { // marked as async
let newDoc = await someAsyncMethod(doc); // so you can then await inside
// do other things
},
err => {
// await was respected, so we get here when done.
if (err) reject(err);
resolve();
}
)
);
もちろん、これをコールバックまたはプレーンなPromise実装のいずれかで適用する方法は常にありますが、これはasync/await
の「砂糖」です。 実際にこれをはるかにきれいに見せます。
NodeJSv10.xおよびMongoDBノードドライバー3.1.x以降
そして、お気に入りのバージョンはAsyncIterator
を使用しています これは、NodeJSv10以降で有効になりました。これは、反復するためのはるかにクリーンな方法です
async function dbanalyze(){
let cursor = db.collection('randomcollection').find()
for await ( let doc of cursor ) {
// do something with the current document
}
}
どの「ある意味で」 for
の使用に関して最初に尋ねられた質問に戻ります for-await-of
を実行できるのでループします ここでの構文は、正しいインターフェースをサポートするiterableをサポートします。そしてCursor
このインターフェースをサポートしています。
好奇心旺盛な方のために、さまざまなカーソル反復手法を示すために、少し前に作成したリストを示します。ジェネレーター関数からの非同期イテレーターのケースも含まれています:
const Async = require('async'),
{ MongoClient, Cursor } = require('mongodb');
const testLen = 3;
(async function() {
let db;
try {
let client = await MongoClient.connect('mongodb://localhost/');
let db = client.db('test');
let collection = db.collection('cursortest');
await collection.remove();
await collection.insertMany(
Array(testLen).fill(1).map((e,i) => ({ i }))
);
// Cursor.forEach
console.log('Cursor.forEach');
await new Promise((resolve,reject) => {
collection.find().forEach(
console.log,
err => {
if (err) reject(err);
resolve();
}
);
});
// Async.during awaits cursor.hasNext()
console.log('Async.during');
await new Promise((resolve,reject) => {
let cursor = collection.find();
Async.during(
(callback) => Async.nextTick(() => cursor.hasNext(callback)),
(callback) => {
cursor.next((err,doc) => {
if (err) callback(err);
console.log(doc);
callback();
})
},
(err) => {
if (err) reject(err);
resolve();
}
);
});
// async/await allows while loop
console.log('async/await while');
await (async function() {
let cursor = collection.find();
while( await cursor.hasNext() ) {
let doc = await cursor.next();
console.log(doc);
}
})();
// await event stream
console.log('Event Stream');
await new Promise((end,error) => {
let cursor = collection.find();
for ( let [k,v] of Object.entries({ end, error, data: console.log }) )
cursor.on(k,v);
});
// Promise recursion
console.log('Promise recursion');
await (async function() {
let cursor = collection.find();
function iterate(cursor) {
return cursor.hasNext().then( bool =>
(bool) ? cursor.next().then( doc => {
console.log(doc);
return iterate(cursor);
}) : Promise.resolve()
)
}
await iterate(cursor);
})();
// Uncomment if node is run with async iteration enabled
// --harmony_async_iteration
console.log('Generator Async Iterator');
await (async function() {
async function* cursorAsyncIterator() {
let cursor = collection.find();
while (await cursor.hasNext() ) {
yield cursor.next();
}
}
for await (let doc of cursorAsyncIterator()) {
console.log(doc);
}
})();
// This is supported with Node v10.x and the 3.1 Series Driver
await (async function() {
for await (let doc of collection.find()) {
console.log(doc);
}
})();
client.close();
} catch(e) {
console.error(e);
} finally {
process.exit();
}
})();