Mongoose: How to use custom id instead of _id

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

When working with MongoDB through Mongoose in Node.js, developers often interact with the default _id field for document identification. However, in certain situations, you may prefer to use a custom ID field. This guide will demonstrate how to implement and work with custom ID fields in Mongoose, covering everything from basic setup to advanced querying techniques.

Understanding Mongoose ID Fields

By default, Mongoose models come with an auto-generated _id field of type ObjectId. While this is suitable for most applications, you might require a custom identifier for your documents due to application logic or database design choices. To do this, you’ll need to define a custom field in your schema and properly configure Mongoose to handle it.

Setting Up Custom ID Field

const mongoose = require('mongoose');

const customIdSchema = new mongoose.Schema({
  customId: { type: String, required: true, unique: true }
  // ...other fields
});
customIdSchema.set('toJSON', {
  virtuals: true,
  versionKey: false,
  transform: (doc, ret) => {
    ret.id = ret._id;
    delete ret._id;
  }
});

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

Creating and Saving Documents with Custom ID

To create a new document with a custom ID, simply set your custom field when you create a new instance of the model. Make sure the ID is unique to avoid duplication errors.

const newCustomDoc = new CustomModel({
  customId: 'uniqueId123',
  // ...other fields
});

newCustomDoc.save()
  .then(doc => console.log(doc))
  .catch(err => console.error(err));

Querying Documents by Custom ID

When querying your documents, you’d use the custom ID field as you would use the standard _id field. The key difference is in your query syntax where you specify your custom ID.

CustomModel.findOne({ customId: 'uniqueId123' })
  .then(doc => console.log(doc))
  .catch(err => console.error(err));

Indexing the Custom ID Field

For optimal performance, ensure your custom ID field is indexed. This will facilitate faster lookups and efficient querying.

customIdSchema.index({ customId: 1 });

Updating Documents using Custom ID

Updates are similar to queries. Identifying which document to update is achieved by using your custom ID in the condition.

CustomModel.findOneAndUpdate({ customId: 'uniqueId123' }, { $set: { fieldToUpdate: newValue } }, { new: true })
  .then(doc => console.log(doc))
  .catch(err => console.error(err));

Advanced Implementation

For more complex applications, you may need to combine custom IDs with references to other collections, transactional operations, or middleware to handle custom ID assignment and validation.

Using Middleware for Custom ID Generation

You can automate the process of generating unique custom IDs by using Mongoose middleware to set the ID before saving a document.

customIdSchema.pre('save', async function() {
  if (this.isNew) {
    this.customId = await generateUniqueId(); // Assuming generateUniqueId is a function you've defined
  }
});

Handling Custom ID References

When using custom IDs in referenced schemas, ensure that the ref attribute in your SchemaTypes points to the correct custom ID field.

const referencedSchema = new mongoose.Schema({
  referencedField: { type: String, ref: 'CustomModel', required: true }
  // ...other fields
});

Conclusion

Using custom ID fields in Mongoose can provide flexibility and adaptability to your MongoDB schema design. By following best practices and understanding how to implement, query, and index custom IDs, you can tailor your Mongoose models to suit unique application requirements.