Sling Academy
Home/Node.js/Mongoose: How to use custom id instead of _id

Mongoose: How to use custom id instead of _id

Last updated: December 30, 2023

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.

Next Article: Mongoose: Reference a schema in another schema (with examples)

Previous Article: Mongoose: How to efficiently work with very large collections

Series: Mongoose.js Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates