April 6, 2023
-
2
Min Read

Seamlessly caching MongoDB Atlas (it's automagic!)

Accelerate MongoDB Atlas with caching—without missing a beat.
Ryan Brown
Headshot of the blog author
by
Ryan Brown
,
,
by
Ryan Brown
by
green squirrel logo for momento
Ryan Brown
,
,
Database

Previously, we showed how Momento Cache outdoes DAX in reducing DynamoDB latencies. Today, we'll work on seamlessly caching applications that use MongoDB Atlas. Read on to see how we reduced latencies to less than 1/3 of the original—with just 1 line of code!​

"Automagic" caching

Developers often hesitate to add caching because there is additional engineering work needed to refactor their code to populate and query the cache. Momento Cache removes that friction. In this example, we extended the popular Mongoose ODM to automatically cache the values for find, count, and distinct queries. Automatic caching with no code changes! It's like magic!

​Using this extended version of Mongoose, every time the application queries MongoDB, it will check Momento first, and if that entry does not exist it will fetch the result from MongoDB and save the result in Momento Cache for subsequent queries.

In our example application, which lives inside a Lambda function, we simply need to call the extension function once to turn on automatic caching (this can be changed to turn on by default as well).


import { Context, APIGatewayProxyEventV2 } from 'aws-lambda';
import { Schema, model, connect } from 'mongoose';
import wrapWithMomento, { setCaching } from './wrap-with-momento';
​
// ... set up the mongoose models
​
wrapWithMomento(); // the cache wrapper here adds the Momento caching to mongoose
​
export const getLeaders = async (game: string) => {
  return await Player.find().where('game').equals(game).sort({ score: 'desc', name: 'asc' }).limit(20);
};
​
export const handler = async (event: any, context: Context) => {
  await connect(`${process.env.MONGODB_URI!}/${process.env.COLLECTION_NAME}`, { connectTimeoutMS: 1000 });
​
  // ... read the game from the HTTP request
​
  const start = new Date();
  const result = await getLeaders(game);
​
  return { elapsed: (new Date()).getTime() - start.getTime(), game, result };
};

​The only difference between the code above and a version without caching is the call to wrapWithMomento() which turns on automatic caching.

Results

To see the results of cached vs uncached reads, we built a second Lambda function that invokes the example application at 20RPS, once against MongoDB Atlas Shared directly and once using our extended Mongoose client that caches results inside Momento Cache.

The average request latency for uncached MongoDB Atlas Shared over the tested 12-hour period was 9.2ms, compared to Momento's average of 2.8ms.

The average request latency for uncached MongoDB Atlas Shared over the tested 12-hour period was 9.2ms, compared to Momento's average of 2.8ms.

There you go. We reduced latency to 1/3 of its original value with 1 line of code! If you use Mongoose in your application, you can do the same!

Try this yourself with our repo on Github! If you use another language, the same principle can be applied to cache automagically—just let us know which language you want to see on our Discord!

Ryan Brown
by
Ryan Brown
,
,
by
Ryan Brown
by
green squirrel logo for momento
by
Ryan Brown
,
,
Author
Ryan Brown

Ryan Brown is a Principal Engineer at Crunchyroll, with a passion for complex problems related to scaling, automation, and resiliency. In his free time, Ryan immerses himself in personal projects and self-directed research, constantly seeking out new tools and exploring different areas of his field. With his extensive knowledge and experience, Ryan is committed to driving innovation and pushing boundaries in the tech industry.

Author
Author
Open