How to use Mongoose without a schema

Updated: December 30, 2023 By: Guest Contributor Post a comment


Mongoose is a popular Object-Document Mapping (ODM) library for MongoDB and Node.js that simplifies interactions with the database by providing a straight-forward, schema-based solution to model application data. However, there are situations when you may want to forgo the rigid structure of a schema, favoring a more flexible approach. This is where schemaless usage of Mongoose comes in handy, especially when dealing with variable data structures that don’t fit well into a defined schema, or when rapidly prototyping. In this tutorial, we’ll explore how to harness the full potential of Mongoose without a strict schema definition.

Getting Started

First, you’ll need to have Node.js and MongoDB installed on your system. Ensure they are both accessible from the command line. Then, create a new directory for our project, navigate to it, and initialize a new Node.js project:

mkdir my-mongoose-noschema

cd my-mongoose-noschema

npm init -y

Now, install Mongoose:

npm install mongoose

Connecting to MongoDB

To connect to MongoDB using Mongoose:

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/my_database', {
  useNewUrlParser: true,
  useUnifiedTopology: true

Defining the Model

Rather than defining a strict schema, you’ll use the Schema-less feature of MongoDB through Mongoose:

const Any = new mongoose.Mongoose().model('Any', new mongoose.Schema({}, { strict: false }));

Basic CRUD Operations

Creating a Record

Without a strict schema, you can insert documents that don’t adhere to a specific structure:

const dynamicDocument = new Any({ name: 'John Doe', hobbies: ['skydiving', 'chess'] });

(async () => {
  try {
    console.log('Document saved successfully.');
  } catch (error) {
    console.error('Error saving document:', error);

Reading Documents

You can also fetch records without needing them to conform to a schema:

(async () => {
  try {
    const documents = await Any.find();
  } catch (error) {
    console.error('Error fetching documents:', error);

Updating Records

Even with schema-less models, updating is done in much the same way:

(async () => {
  try {
    const result = await Any.updateOne({ name: 'John Doe' }, { $set: { age: 30 } });
    console.log('Document updated:', result);
  } catch (error) {
    console.error('Error updating document:', error);

Deleting Records

Deletion remains uncomplicated:

(async () => {
  try {
    const result = await Any.deleteOne({ name: 'John Doe' });
    console.log('Document deleted:', result);
  } catch (error) {
    console.error('Error deleting document:', error);

Advanced Usage

When considering advanced usage, think about using discriminators for documents with certain common fields, or hybrid schema design which allows defined structure for commonly used fields, while still permitting arbitrary fields.

Handling Data Validation

Even without a schema, you may want to validate your data before saving to MongoDB:

Any.validate(dynamicDocument, (error) => {
  if (error) {
    console.error('Validation error:', error);

Indexing for Performance

Indexes can still be added for a performance boost, particularly on fields that will be queried frequently:

Any.createIndexes({ 'hobbies': 1 });


While schemas provide a critical underpinning of structure to Mongoose and MongoDB interactions, schemaless operation is a valid and powerful approach when flexibility is paramount. Through strategic thought and an understanding of how to appropriately use this unstructured data type, you can make full use of Mongoose’s dynamic and powerful features.

Remember that with great power comes great responsibility, and operating without schemas should be done with care to prevent potential issues like data inconsistency and difficulty in later attempting to enforce a schema on data that was hitherto unstructured. Happy coding!