Using Async/Await with Mongoos
Queries in Mongoose 4.x have a .then() function, so you don't need any extra work to use mongoose with async/await:
const mongoose = require('mongoose');
async function run() {
// No need to `await` on this, mongoose 4 handles connection buffering
// internally
mongoose.connect('mongodb://localhost:27017/test');
await mongoose.connection.dropDatabase();
const MyModel = mongoose.model('Test', new mongoose.Schema({ name: String }));
await MyModel.create({ name: 'Val' });
// Prints an array with 1 element, the above document
console.log(await MyModel.find());
}
run().catch(error => console.error(error.stack));
Async/await makes interacting with mongoose cursors much more elegant. While you still can use cursors as a stream with async/await, it's much more elegant to use the next()
function. Fundamentally, a mongoose cursor is an object with a next()
function that returns a promise which resolves to the next document in the query result, or null
if there are no more documents.
const mongoose = require('mongoose');
async function run() {
mongoose.connect('mongodb://localhost:27017/test');
await mongoose.connection.dropDatabase();
const MyModel = mongoose.model('Test', new mongoose.Schema({ name: String }));
await MyModel.create({ name: 'Val' }, { name: 'Varun' });
// A cursor has a `.next()` function that returns a promise. The promise
// will resolve to the next doc if there is one, or null if they are no
// more results.
const cursor = MyModel.find().sort({name: 1 }).cursor();
for (let doc = await cursor.next(); doc != null; doc = await cursor.next()) {
// Prints "Val" followed by "Varun"
console.log(doc.name);
}
}
run().catch(error => console.error(error.stack));
Mongoose cursors also have a neat eachAsync()
function that lets you do some rudimentary functional programming with async/await. The eachAsync()
function executes a (potentially async
) function for each document that the cursor returns. If that function returns a promise, it will wait for that promise to resolve before getting the next document. This is the easiest way to exhaust a cursor in mongoose.
const mongoose = require('mongoose');
async function run() {
mongoose.connect('mongodb://localhost:27017/test');
await mongoose.connection.dropDatabase();
const MyModel = mongoose.model('Test', new mongoose.Schema({ name: String }));
await MyModel.create({ name: 'Val' }, { name: 'Varun' });
// A cursor has a `.next()` function that returns a promise. The promise
// will resolve to the next doc if there is one, or null if they are no
// more results.
const cursor = MyModel.find().sort({name: 1 }).cursor();
let count = 0;
console.log(new Date());
await cursor.eachAsync(async function(doc) {
// Wait 1 second before printing first doc, and 0.5 before printing 2nd
await new Promise(resolve => setTimeout(() => resolve(), 1000 - 500 * (count++)));
console.log(new Date(), doc);
});
}
run().catch(error => console.error(error.stack));