19

I'm using Koa.js framework and Mongoose.js module.

Normally to get a result from MongoDB I code like this:

var res = yield db.collection.findOne({id: 'my-id-here'}).exec();

But I need to execute this line for every element of an array named 'items'.

items.forEach(function(item) {
  var res = yield db.collection.findOne({id: item.id}).exec();
  console.log(res)  // undefined
});

But this code doesn't run as yield is in the function. If I write this:

items.forEach(function *(item) {
  var res = yield db.collection.findOne({id: item.id}).exec();
  console.log(res)  // undefined
});

I'm not getting the result in res variable either. I tried to use 'generator-foreach' module but that didn't worked like this.

I know that this is my lack of knowledge about the language literacy of Node.js. But can you guys help me finding a way how to do this?

Mazhar Ahmed
  • 1,523
  • 2
  • 24
  • 41

3 Answers3

28

You can yield arrays, so just map your async promises in another map

var fetchedItems = yield items.map((item) => {
   return db.collection.findOne({id: item.id});
});
Umidbek
  • 1,504
  • 12
  • 26
12

The accepted answer is wrong, there is no need to use a library, an array is already an iterable.

This is an old question, but since it has no correct answer yet and it appears on the first page on google search for the key terms "iterators and forEach" I will respond the question:

There is no need to iterate over an array, since an array already conforms to the iterable API.

inside your generator just use "yield* array" (note the * ) yield* expression is used to delegate to another generator or iterable object

Example:

let arr = [2, 3, 4];

    function* g2() { 
      yield 1;
      yield* arr;
      yield 5;
    }

    var iterator = g2();

    console.log(iterator.next()); // { value: 1, done: false }
    console.log(iterator.next()); // { value: 2, done: false }
    console.log(iterator.next()); // { value: 3, done: false }
    console.log(iterator.next()); // { value: 4, done: false }
    console.log(iterator.next()); // { value: 5, done: false }
    console.log(iterator.next()); // { value: undefined, done: true }

For examples and in depth information visit: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*

Jorge Rivera
  • 766
  • 1
  • 11
  • 19
7

Thanks guys, I've done this using the 'CO' module. Thanks.

var co = require('co');

items.forEach(co(function* (item) {
  var img = yield db.collection.findOne({id: item.id}).exec();
}));

EDIT: With the latest version of CO, you need co.wrap() for this to work.

joncodo
  • 2,298
  • 6
  • 38
  • 74
Mazhar Ahmed
  • 1,523
  • 2
  • 24
  • 41