forEach using generators in Node.js
Asked Answered
R

3

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?

Ranita answered 16/7, 2014 at 8:24 Comment(2)
What exactly did you try with generator-foreach?Lordan
I just replaced forEach with the generator-foreach. The rest of the code is same. Can you modify my code snippet and make sure that it's working?Ranita
R
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.

Ranita answered 17/7, 2014 at 5:0 Comment(5)
This does not work because item === items when it's wrapped with co()Fidellia
If you use a standard for loop for (x=0;x<items.length;x++), it'll work because there's no callback, thus allowing you to use yield without wrapping it inside another co.Fidellia
I did the same afterword though. Good job finding it. Thanks.Ranita
co has changed a bit. Now you need co.wrap() then this example worksMiddleaged
@Fidellia 's comment is the solution. forEach and anoy functions wrapped in co() does not seem to work, to get it working you need to use the for loop insteadQuintero
M
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});
});
Moiety answered 14/8, 2015 at 3:24 Comment(1)
This is much simpler and should be the accepted answer.Intemperate
P
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*

Prochoras answered 18/7, 2016 at 21:24 Comment(0)
R
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.

Ranita answered 17/7, 2014 at 5:0 Comment(5)
This does not work because item === items when it's wrapped with co()Fidellia
If you use a standard for loop for (x=0;x<items.length;x++), it'll work because there's no callback, thus allowing you to use yield without wrapping it inside another co.Fidellia
I did the same afterword though. Good job finding it. Thanks.Ranita
co has changed a bit. Now you need co.wrap() then this example worksMiddleaged
@Fidellia 's comment is the solution. forEach and anoy functions wrapped in co() does not seem to work, to get it working you need to use the for loop insteadQuintero

© 2022 - 2024 — McMap. All rights reserved.