当前位置: 首页 > 面试题库 >

具有异步子任务的异步游标迭代

丌官坚秉
2023-03-14
问题内容

我想对不带数字键(_id)的mongoDB集合执行迭代。集合只有一个随机字符串作为_id,并且集合的大小很大,因此使用来将整个文档加载到RAM
.toArray()上不是可行的选择。另外,我想对每个元素执行异步任务。的使用.map()或者.each().forEach()是因为任务的异步性质的限制。我尝试使用上述方法运行任务,但它确实与异步任务冲突,返回了未完成的承诺而不是正确的结果。

async function dbanalyze(){

  let cursor = db.collection('randomcollection').find()
  for(;;){
    const el = cursor.hasNext() ? loaded.next() : null;
    if(!cursor) break
    await performAnalyze(cursor) // <---- this doesn't return a document but just a cursor object
  }

}

我怎样才能仅使用mongoDB集合进行迭代for()


问题答案:

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()is
时进行循环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标志还使 “更加实用”
,因为它的一个常见缺陷是不能简单地处理“内部”异步调用,但是现在有了这些标志,您就可以轻松地做到这一点,尽管可以承认,因为 必须*
使用回调,您可能希望将其包装在Promise中:Cursor.forEach() __
*

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实际上使它看起来更简洁。

NodeJS v10.x和MongoDB Node驱动程序3.1.x及更高版本

最喜欢的版本使用的AsyncIterator是现在已在NodeJS v10及更高版本中启用的版本。这是一种更干净的迭代方式

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此处进行语法支持可迭代的语法,该语法支持正确的接口。并且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();
  }

})();


 类似资料:
  • 我对Java比较陌生。。 我正在编写一个Android应用程序,现在我将回顾我的代码,整理并坚持我的编码结构,使之更符合最佳实践风格。 我正在构建我认为合适的方法和类,以避免产生大量重复代码。我发现自己正在尝试创建一个类(例如HeavyStuff.java),其中包含几个AsyncTask方法(例如MyTask1和MyTask2)。从活动调用类时,我希望在某个点执行MyTask1,在其他点执行My

  • 主要内容:本节引言:,1.相关概念,2.AsyncTask全解析:,3.AsyncTask使用示例:,本节小结:本节引言: 本节给大家带来的是Android给我们提供的一个轻量级的用于处理异步任务的类:AsyncTask,我们一般是 继承AsyncTask,然后在类中实现异步操作,然后将异步执行的进度,反馈给UI主线程~ 好吧,可能有些概念大家不懂,觉得还是有必要讲解下多线程的概念,那就先解释下一些概念性的东西吧! 1.相关概念 1)什么是多线程: 答:先要了解这几个名称:应用程序,进程,线程,

  • 我试图在这个类中实现异步任务,但问题是我在我的程序中调用了函数,该函数返回一个值,我不知道该把它放在哪里。在异步任务中,我应该在哪里定义?我得到以下例外 以下是我的主要课程: 这是我的解析类:公共类解析{ List headlines列出链接;列表描述;列出lstDate列出新日期;//字符串a,b,c,d;public InputStream getInputStream(URL URL){ t

  • 我有一个方法要调用一个存储函数。我希望它异步地完成它的工作。这就是我所拥有的,但似乎.doWork()从未启动,因为当我调用<code>getDao时。deleteAll(),存储的函数不运行。 我看到记录器已经记录了,但它从未到达为什么会发生这种情况?

  • 这可能是一个更巧妙的问题,但我在ViewComponent类中有以下方法 所以我的问题是我应该采取什么方法?让异步在那里与警告无关,还是有一个解决方案/修复这个警告?它对我的项目有那么大的影响吗? 谢了!

  • 8.2 使用异步任务 注意:本节所介绍的功能要求 vim 编译包括 +job 特性。 8.2.1 简单任务体验 前文说到,Vim 的异步任务主要是针对外部命令的。那我们就先以最简单最常见的系统命 令 ls 为例,其功能是列出当前目录下的文件,若在 Windows 操作系统下或可用 dir 命令代替。 首先请在 shell 中进入一个非空目录,便于实践,并在 shell 中执行如下命令: $ ls