MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Lặp lại con trỏ không đồng bộ với tác vụ con không đồng bộ

Cursor.hasNext() phương thức cũng là "không đồng bộ", vì vậy bạn cần phải await Cũng vậy. Tương tự với Cursor.next() . Do đó, việc sử dụng "vòng lặp" thực sự phải là 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
  }

}

Như đã lưu ý trong các nhận xét, cuối cùng Cursor.hasNext() sẽ trả về false khi con trỏ thực sự bị cạn và Cursor.next() là thứ thực sự đang truy xuất từng giá trị từ con trỏ. Bạn có thể thực hiện các cấu trúc khác và break vòng lặp khi hasNext()false , nhưng nó tự cho mình một while một cách tự nhiên hơn .

Đây vẫn là "không đồng bộ", vì vậy bạn cần phải await giải pháp lời hứa trên mỗi và đó là thực tế chính mà bạn đã bỏ lỡ.

Đối với Cursor.map() , thì có thể bạn đang thiếu điểm mà nó có thể được đánh dấu bằng async gắn cờ trên chức năng được cung cấp:

 cursor.map( async doc => {                   // We can mark as async
    let newDoc = await someAsyncMethod(doc);  // so you can then await inside
    return newDoc;
 })

Nhưng bạn vẫn thực sự muốn "lặp lại" điều đó ở đâu đó, trừ khi bạn có thể thoát khỏi bằng cách sử dụng .pipe() đến một số điểm đến đầu ra khác.

Ngoài ra, async/await cờ cũng tạo ra Cursor.forEach() "lại thiết thực hơn" , vì đó là một lỗ hổng phổ biến là không thể xử lý đơn giản một lệnh gọi không đồng bộ "bên trong", nhưng với các cờ này, giờ đây bạn có thể làm như vậy một cách dễ dàng, mặc dù phải thừa nhận vì bạn phải sử dụng một lệnh gọi lại, bạn có thể muốn kết thúc điều này trong một Lời hứa:

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();
    }
  )
);

Tất nhiên luôn có nhiều cách để áp dụng điều này với lệnh gọi lại hoặc triển khai Promise thuần túy, nhưng đó là "đường" của async/await hơn thực tế là làm cho cái này trông gọn gàng hơn nhiều.

Trình điều khiển NodeJS v10.x và MongoDB Node 3.1.x trở lên

Và phiên bản yêu thích sử dụng AsyncIterator hiện đã được kích hoạt trong NodeJS v10 trở lên. Đó là một cách lặp lại dễ dàng hơn nhiều

async function dbanalyze(){

  let cursor = db.collection('randomcollection').find()
  for await ( let doc of cursor ) {
    // do something with the current document
  }    
}

"theo một cách nào đó" quay lại câu hỏi ban đầu được hỏi về việc sử dụng for vòng lặp vì chúng ta có thể thực hiện for-await-of cú pháp ở đây trước khi hỗ trợ có thể lặp lại hỗ trợ giao diện chính xác. Và Cursor không hỗ trợ giao diện này.

Nếu bạn tò mò, đây là danh sách mà tôi đã soạn thảo cách đây ít lâu để trình diễn các kỹ thuật lặp lại con trỏ khác nhau. Nó thậm chí còn bao gồm một trường hợp cho Trình lặp không đồng bộ từ một hàm trình tạo:

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();
  }

})();



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Phần trăm các điều kiện OR được so khớp trong mongodb

  2. MongoError:Tùy chọn 'con trỏ' là bắt buộc, ngoại trừ trường hợp tổng hợp với đối số giải thích

  3. Đối số được chuyển vào phải là một chuỗi gồm 24 ký tự hex - tôi nghĩ là

  4. Làm cách nào để lấy lại không gian đã xóa mà không có `db.repairDatabase ()`?

  5. thay đổi kiểu mongodb thành mảng