As you said, listening to the end event in a stream is useless in itself. The thread does not know and does not care about what you are doing with the data in your data handler, so you will need to write code to track your own migrateAccount state.
If it were me, I would rewrite this entire section. If you use the readable event with .read() in your stream, you can read as many items as possible at a time, in your opinion. If this is not a problem. If it's 30, great. The reason you do this is because you will not overwhelm everything that works with data coming from the stream. Like now, if AccountStream is fast, your application will surely crash at some point.
When you read an element from the stream and begin work, accept the promise that you will return (use Bluebird or similar) and throw it into the array. When the promise is resolved, remove it from the array. When the thread ends, attach the .done() handler to .all() (basically, making one big promise from all the promises still in the array).
You can also use a simple counter for your work.
source share