Skip to main content

Schema IDs in Mongoose

Schema IDs in Mongoose | Rustcode

Schema IDs in Mongoose

Every MongoDB document requires a unique identifier known as the _id field. Mongoose automatically adds this _id field of type ObjectId to your schemas unless explicitly disabled. This article explains how Mongoose handles schema IDs by default, ways to customize them, and important options you can use to control ID behavior.


Default _id Field

By default, Mongoose adds an _id field of type ObjectId to every document in your schema. This field acts as the primary key for the document and is automatically generated when you create a new document instance.

const schema = new mongoose.Schema({
  name: String
});

const Model = mongoose.model('Model', schema);

const doc = new Model({ name: 'Example' });
console.log(doc._id); // Outputs a unique ObjectId

Using Custom IDs

You can override Mongoose's default _id field by specifying your own _id path in the schema. However, if you do this, you must manually set IDs before saving documents, as Mongoose requires an _id on each top-level document.

const customSchema = new mongoose.Schema({
  _id: String,
  name: String
});

const CustomModel = mongoose.model('CustomModel', customSchema);

const doc = new CustomModel({ _id: 'custom-id-123', name: 'Custom' });

doc.save()
  .then(() => console.log('Document saved with custom _id'))
  .catch(err => console.error(err));

Disabling _id Field in Subdocuments

While Mongoose requires the _id field for top-level documents, you can disable it in subdocuments (nested schemas) by setting { _id: false } in the schema options:

const childSchema = new mongoose.Schema({
  name: String
}, { _id: false });

const parentSchema = new mongoose.Schema({
  children: [childSchema]
});

const Parent = mongoose.model('Parent', parentSchema);

const doc = new Parent({
  children: [{ name: 'Child 1' }, { name: 'Child 2' }]
});

console.log(doc.children[0]._id); // undefined

The id Virtual Getter

Mongoose adds a virtual getter id by default, which returns the string representation of the _id field (typically the hex string of an ObjectId). You can disable this behavior by passing { id: false } when creating your schema.

const schema = new mongoose.Schema({
  name: String
}, { id: false });

const Model = mongoose.model('Model', schema);
const doc = new Model({ name: 'No ID Virtual' });

console.log(doc.id); // undefined

Best Practices

  • Let Mongoose manage the default _id unless you have a specific reason to provide custom IDs.
  • Always ensure that top-level documents have an _id to avoid save errors.
  • Disable _id only on subdocuments where IDs are unnecessary.
  • Use the id virtual for simplified string representation but disable it if you need to reduce overhead.
  • Understand ObjectId structure for efficient querying and indexing.

Quick Reference Table

Feature Description Notes
_id by default Automatically added ObjectId unique ID for documents Required for all top-level docs
Custom _id Override default with your own type & value Must manually set before saving
Disable _id Turn off _id only for subdocuments Useful to reduce document size
id virtual String representation of _id Enabled by default, can be disabled

Conclusion

The _id field is a fundamental part of MongoDB and Mongoose documents, providing unique identification and enabling efficient queries. Mongoose simplifies its usage by automatically generating ObjectId values but also offers flexibility for custom IDs and optimization in nested schemas. Understanding these ID mechanisms is essential for effective schema design and data management.

Comments