Node.js nodejs异步在createReadStream内等待

Node.js nodejs异步在createReadStream内等待,node.js,async-await,nodejs-stream,Node.js,Async Await,Nodejs Stream,我正在逐行读取CSV文件,并在MongoDB中插入/更新。预期产出将为 1.console.logrow; 2.console.logcursor; 3.console.logstream 但是获得像这样的输出 1.console.logrow; console.logrow;console.logrow;console.logrow;console.logrow。。。。。。。。。。。。 2.console.logcursor; 3.console.logstream; 请让我知道我错过了什么

我正在逐行读取CSV文件,并在MongoDB中插入/更新。预期产出将为 1.console.logrow; 2.console.logcursor; 3.console.logstream

但是获得像这样的输出 1.console.logrow; console.logrow;console.logrow;console.logrow;console.logrow。。。。。。。。。。。。 2.console.logcursor; 3.console.logstream; 请让我知道我错过了什么

const csv = require('csv-parser');
const fs = require('fs');

var mongodb = require("mongodb");

var client = mongodb.MongoClient;
var url = "mongodb://localhost:27017/";
var collection;
client.connect(url,{ useUnifiedTopology: true }, function (err, client) {

  var db = client.db("UKCompanies");
  collection = db.collection("company");
  startRead();
});
var cursor={};

async function insertRec(row){
  console.log(row);
  cursor = await collection.update({CompanyNumber:23}, row, {upsert: true});
  if(cursor){
    console.log(cursor);
  }else{
    console.log('not exist')
  }
  console.log("stream");
}



async function startRead() {
  fs.createReadStream('./data/inside/6.csv')
    .pipe(csv())
    .on('data', async (row) => {
      await insertRec(row);
    })
    .on('end', () => {
      console.log('CSV file successfully processed');
    });
}

在本例中,这是预期的行为,因为当数据流中有可用数据时,on-data侦听器异步触发insertRec。这就是为什么第一行insert方法是并行执行的。如果要控制此行为,可以在创建读取流时使用highWaterMark属性。这样,您将一次获得一条记录,但我不确定您的用例是什么

像这样的

fs.createReadStream(`somefile.csv`, {
  "highWaterMark": 1
})
同样,你也不是在等待你的startRead方法。我会将它包装在承诺中,并最终解决它,否则您将不知道处理何时完成。差不多

function startRead() {
  return new Promise((resolve, reject) => {
    fs.createReadStream(`somepath`)
      .pipe(csv())
      .on("data", async row => {
        await insertRec(row);
      })
      .on("error", err => {
        reject(err);
      })
      .on("end", () => {
        console.log("CSV file successfully processed");
        resolve();
      });
  });

}

在本例中,这是预期的行为,因为当数据流中有可用数据时,on-data侦听器异步触发insertRec。这就是为什么第一行insert方法是并行执行的。如果要控制此行为,可以在创建读取流时使用highWaterMark属性。这样,您将一次获得一条记录,但我不确定您的用例是什么

像这样的

fs.createReadStream(`somefile.csv`, {
  "highWaterMark": 1
})
同样,你也不是在等待你的startRead方法。我会将它包装在承诺中,并最终解决它,否则您将不知道处理何时完成。差不多

function startRead() {
  return new Promise((resolve, reject) => {
    fs.createReadStream(`somepath`)
      .pipe(csv())
      .on("data", async row => {
        await insertRec(row);
      })
      .on("error", err => {
        reject(err);
      })
      .on("end", () => {
        console.log("CSV file successfully processed");
        resolve();
      });
  });

}
在startRead函数中,当insertRec正在处理时,wait insertRec不会停止更多数据事件的流动。因此,如果您不希望在insertRec完成之前运行下一个数据事件,则需要暂停,然后恢复流

async function startRead() {
  const stream = fs.createReadStream('./data/inside/6.csv')
    .pipe(csv())
    .on('data', async (row) => {
      try {
        stream.pause();
        await insertRec(row);
      } finally {
        stream.resume();
      }
    })
    .on('end', () => {
      console.log('CSV file successfully processed');
    });
}
仅供参考,如果insertRec失败,您还需要一些错误处理。

在startRead函数中,在insertRec处理过程中,等待insertRec不会停止更多数据事件的流动。因此,如果您不希望在insertRec完成之前运行下一个数据事件,则需要暂停,然后恢复流

async function startRead() {
  const stream = fs.createReadStream('./data/inside/6.csv')
    .pipe(csv())
    .on('data', async (row) => {
      try {
        stream.pause();
        await insertRec(row);
      } finally {
        stream.resume();
      }
    })
    .on('end', () => {
      console.log('CSV file successfully processed');
    });
}

仅供参考,如果insertRec失败,您还需要一些错误处理。

设置highWaterMark不允许您限制数据事件的速率。OP应该实现一个可写流,该流可以配置为逐个文档写入,或者写入大量文档。highWaterMark允许您控制内存压力。@jorgenkg这是真的。感谢您的澄清。@jorgenkg-对于在对象模式下运行的流,highWaterMark指定对象总数-是-将在读/写流的内部缓冲区中缓冲的对象数。对象总是通过写入一次处理一个。highWaterMark表示可以为流实例缓冲多少对象。设置highWaterMark不允许限制数据事件的速率。OP应该实现一个可写流,该流可以配置为逐个文档写入,或者写入大量文档。highWaterMark允许您控制内存压力。@jorgenkg这是真的。感谢您的澄清。@jorgenkg-对于在对象模式下运行的流,highWaterMark指定对象总数-是-将在读/写流的内部缓冲区中缓冲的对象数。对象将始终通过写入一次处理一个。highWaterMark表示可以为流实例缓冲多少对象。Thnks@jfriend00Thnks@jfriend00