How to create a fixed-size collection with MongooseJS

Updated: February 1, 2024 By: Guest Contributor Post a comment

Introduction

Dealing with fast-growing databases can present significant challenges, particularly when you want to maintain a fixed-size collection where old data is seamlessly removed to make room for new entries. This behavior is especially useful in systems where only the most recent data is relevant, such as logging systems or caches.

This tutorial will guide you through the process of creating a fixed-size collection in MongoDB using MongooseJS, a popular ODM (Object Document Mapper) for Node.js. We’ll also explore strategies for old document removal and the use of capped collections.

Prerequisites

  • Basic knowledge of JavaScript and Node.js.
  • Node.js and npm (Node Package Manager) installed.
  • MongoDB database and MongooseJS set up in your project.

Working with Capped Collections

In MongoDB, capped collections are fixed-size collections that support high-throughput operations. They automatically remove the oldest documents when they reach the size limit. To employ this feature using Mongoose, you must define a capped collection at creation.

Step 1: Defining a Schema for a Capped Collection

const mongoose = require('mongoose');
const { Schema } = mongoose;

const logSchema = new Schema({
  // Your schema fields
}, { capped: { size: 1024, max: 5000, autoIndexId: true } });

const Log = mongoose.model('Log', logSchema);

The capped option takes an object with several parameters:

  • size – The maximum size in bytes of the collection.
  • max – The maximum number of documents allowed in the collection.
  • autoIndexId – A Boolean indicating if the _id field should be indexed. This is true by default for capped collections in MongoDB.

Note that once a capped collection has been created, modifying these capped options isn’t possible; the collection must be dropped and re-created for changes to take effect.

Step 2: Creating and Inserting Documents

const logEntry = new Log({
  message: 'This is a log message.',
  level: 'info',
  createdAt: new Date()
});

logEntry.save(err => {
  if (err) console.error(err);
  console.log('Log entry saved successfully.');
});

As you add log entries to the collection, MongoDB manages the document removal process to ensure the collection size does not exceed the specified limits.

Step 3: Handling Full Collections

When a capped collection fills up, the oldest documents will be removed as new ones come in. For many use cases, this is the desired behavior since it creates a ‘rolling’ data window. However, this also means you can potentially lose data before consuming or processing it. It is therefore crucial to anticipate this behavior in your application logic.

Using Custom Logic to Manage Fixed-size Collections

If the default behavior of capped collections does not meet your needs, you might elect to manage collection size with custom application logic.

Custom Logic Example:

Log.create({/* document data */}, (err, newLog) => {
  if (err) {
    // Handle errors
  } else {
    Log.countDocuments({}, (err, count) => {
      if (count > 5000) {
        Log.findOne().sort('createdAt').exec((err, oldest) => {
          if (oldest) oldest.remove();
        });
      }
    });
  }
});

This code manually checks the number of documents after each insertion. If the document count exceeds the threshold, it finds and removes the oldest document. This process is less efficient than using a capped collection, since it adds overhead to each write operation.

Managing Indexes and Performance

When working with fixed-size collections, indexing is vital for performance – particularly for searching and sorting operations. For capped collections, MongoDB automatically creates an index on the _id field. For custom collection management, ensure that your fields, which are commonly queried or sorted on, are properly indexed.

Conclusion

Fixed-size collections are an excellent way to manage data that has a limited shelf-life or where only the most recent records are needed. Using MongooseJS with MongoDB’s inbuilt capped collection feature, you can create fixed-size collections that automatically handle the removal of old data. However, if capped collections do not offer the flexibility your application needs, you can alternatively implement custom logic to prune older documents.

Remember to review the performance and indexing considerations as part of this process. Whether you go for the simplicity of capped collections or the fine-grained control of custom logic, you now know how to ensure your MongoDB collections remain within a manageable and predictable size.