By default, mongoose .find() , of course, returns all the results as an "array", so it will always use memory with large results, so this leaves the "stream" interface.
The main problem is that you are using the stream interface (since it is inherited from the main stream node) the "fires" event and the event handler associated with it are executed continuously.
This means that even with the "thread", your subsequent actions in the event handler "stack" upwards, at least consuming a lot of memory and, possibly, waiting for the call stack if there are additional asynchronous processes.
So, the best thing you can do is to “limit” the actions in your stream processing. This is as simple as calling the .pause() method:
var stream = model.find().stream();
So .pause() stops the events in the thread that throws, and this allows you to perform actions in the event handler before continuing, so that they do not all arrive immediately.
When your processing code is complete, you call .resume() either directly inside the block, as shown here in the callback block of any asynchronous action performed inside the block. Note that the same rules apply for asynchronous actions, and that "everyone" should signal completion before you call a resume.
There are other optimizations that can be applied as well, and you might find that the available queue processing or asynchronous flow control modules are available to help you achieve better performance while doing this in parallel.
But basically think of .pause() , then process and .resume() to continue to avoid a lot of memory in your processing.
Also, be aware of your “exits” and likewise try to use the “stream” again if you are creating something to answer. All this will be in vain if the work that you do just actually creates another variable in memory, so it helps to realize this.