等到处理完mongoDB查询中的所有项目后再继续

时间:2017-09-27 15:17:32

标签: javascript node.js mongodb loops settimeout

我正在开展一个非常复杂的项目,其中必须处理许多mongoDB查询才能显示数据。现在,当对大量数据执行查询时,并不是所有数据都会在页面加载后立即显示。现在我在使用next()函数之前通过设置超时函数来修复该问题。

所以这就是调用其中一个函数的地方:

router.get('/playwall', account.checkSession, playwalls.get, function(req, res, next) {
  res.render('dashboard/playwalls/index');
});

检查用户是否已登录后,playwalls.get功能将触发。这就是该功能现在的工作方式:

const playwalls = {
  /* GET ALL PLAYWALLS FOR THAT USER, FOR ADMIN GET THEM ALL
  -------------------------------------------------------------- */
  get(req, res, next) {
    req.session.playwalls = [];
    const dataCollection = db.collection('data');
    const data = dataCollection.find({});
    console.log(typeof data)
    const today = new Date();
    data.forEach(function(d) {
      console.log(data.length)
      if(d.admin == req.session.userData.username || req.session.userData.role == 'admin') {
        const expireDate = new Date(d.date);
        if(expireDate < today && d.status == 'actief') {
          playwalls.editStatus(d, req, res, next);
        }
        req.session.playwalls.push(d);
      }
    })
    setTimeout(function() {
      next();
    }, 1000)
  },
  // Here the rest of the methods
}

我的问题是;如果next()循环已处理查询返回的所有文档,我怎样才能确保仅data.forEach函数被触发?所以我可以摆脱setTimeout()函数。

希望我的问题很明确,有人可以帮助我。我在互联网上环顾四周,但无法找到合适的答案。

提前致谢!

3 个答案:

答案 0 :(得分:2)

您应该使用Cursor.toArray,这样您就可以同步方式迭代文档,如果您需要在forEach回调中执行某项异步作业,则可以使用Promise&#39 ; S

const playwalls = {
    /* GET ALL PLAYWALLS FOR THAT USER, FOR ADMIN GET THEM ALL
    -------------------------------------------------------------- */
    get(req, res, next) {
        req.session.playwalls = [];
        const dataCollection = db.collection('data');
        const data = dataCollection.find({});
        console.log(typeof data)
        const today = new Date();
        data.toArray(function (err, documents) {
            if (err) {
                return next(err);
            }
            documents.forEach(function (d) {
                console.log(data.length)
                if (d.admin == req.session.userData.username || req.session.userData.role == 'admin') {
                    const expireDate = new Date(d.date);
                    if (expireDate < today && d.status == 'actief') {
                        playwalls.editStatus(d, req, res, next);
                    }
                    req.session.playwalls.push(d);
                }
            })
            next();
        })
    }, // Here the rest of the methods
}

答案 1 :(得分:1)

如何定义返回promise的函数。

所以,将forEach拉出一个单独的函数:

function promisedForEach(data) {
    return new Promise(resolve => {
        // your code
        resolve('ready')
     }
 }

然后调用函数代替forEach:

promisedForEach(data).then( /* carry on */ ) 

答案 2 :(得分:0)

我认为setTimeout不会起作用,因为一切都必须在同一个线程中发生。因此,setTimeout只会在轮到执行时冻结。

另一种方法是使用rxjs观察者。 https://github.com/ReactiveX/RxJS当您想要在呈现页面之前等待应用程序的其他部分(例如中间件)中的内容时,这可能很有用。

您可以执行以下操作。我没有测试过这个。我会给你一些想法;

global.Rx = require('rxjs/Rx');

router.get('/playwall', function(req, res) {
  const myProcesses = {
    ready:  new Rx.Subject(false),
    loading:  false,
    readiness: {
      process1: {
        ready: false
      },
      process2: {
        ready: false
      },
      process3: {
        ready: false
      }
    },
    checkReadiness: function (){
      if (
        this.readiness.process1==true
        && this.readiness.process2==true
        && this.readiness.process3==true
      ) {
        this.loading = false;
        this.ready.next(true);
      }
    },
  };
  //asynchronous process
  (function (){
    anObject.fetchAll().then(function (results){
      myProcesses.readiness.process1 = true;
      myProcesses.checkReadiness();
    })
  })();

  //another asynchronous process
  (function (){
    anObject2.fetchAll().then(function (results){
      myProcesses.readiness.process2 = true;
      myProcesses.checkReadiness();
    })
  })();

  //another asynchronous process
  (function (){
    anObject2.fetchAll().then(function (results){
      myProcesses.readiness.process3 = true;
      myProcesses.checkReadiness();
    })
  })();

  //When all asynchronous processes have been completed
  myProcesses.ready.subscribe({next: (v) => {
    if (v==true){
      res.render('ejs/products/checkout', {});
    }
  }});
});