You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何为Mongoose Schema中的internalId字段实现自增累计值

Implement Auto-Incrementing internalId for Mongoose Person Schema

Let's solve your problem of adding a sequential auto-incrementing internalId to your Person documents. Using a global variable isn't reliable—restarting your server would reset the count, and you'd hit duplicate ID issues with multiple server instances. Instead, we'll use a dedicated counter collection to safely persist and increment the ID value.

Step 1: Create a Counter Schema & Model

First, we need a separate collection to track the current maximum ID for each model. This ensures the count stays intact across server restarts and handles concurrency safely with atomic database operations.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Counter schema to track auto-increment IDs
const counterSchema = new Schema({
  modelName: { 
    type: String, 
    required: true, 
    unique: true // Ensures one counter per model
  },
  currentId: { 
    type: Number, 
    default: 0 
  }
});

const Counter = mongoose.model('Counter', counterSchema);

Step 2: Modify the Person Schema's Pre-Save Hook

Update your existing pre('save') hook to fetch and increment the counter before saving a new Person document. We'll use findOneAndUpdate—an atomic operation that prevents race conditions when multiple documents are created at the same time.

const personSchema = new Schema({
  name: { type: String },
  age: { type: Number },
  internalId: { type: Number },
});

personSchema.pre('save', async function(next) {
  // Only run this logic for new documents
  if (this.isNew) {
    try {
      // Find or create the counter for Person model, then increment it
      const counter = await Counter.findOneAndUpdate(
        { modelName: 'Person' },
        { $inc: { currentId: 1 } }, // Atomically increment the current ID
        { new: true, upsert: true } // Return updated doc; create if it doesn't exist
      );
      
      // Assign the incremented ID to internalId
      this.internalId = counter.currentId;
      
      // Note: Mongoose automatically adds an `id` field (string version of _id)
      // So your original line `this.id = this._id;` is redundant and can be removed
      next();
    } catch (err) {
      // Pass any errors to the next middleware
      next(err);
    }
  } else {
    // Skip for existing documents
    next();
  }
});

const Person = mongoose.model("Person", personSchema);
exports.Person = Person;
exports.Counter = Counter; // Export if you need to initialize counters manually

Key Notes & Considerations

  • Persistence: The counter is stored in your database, so it won't reset when your server restarts.
  • Concurrency Safety: findOneAndUpdate is an atomic operation, so even if multiple requests try to create a Person at the same time, you won't get duplicate internalId values.
  • Existing Collections: If you already have Person documents in your database, you'll need to initialize the counter manually. Run this once (e.g., in a script or your server startup):
    // Replace 100 with the highest existing internalId in your Person collection
    await Counter.findOneAndUpdate(
      { modelName: 'Person' },
      { currentId: 100 },
      { upsert: true }
    );
    
  • Reusability: You can reuse this counter pattern for any other models that need auto-incrementing IDs—just use a different modelName value.

内容的提问来源于stack exchange,提问作者colla

火山引擎 最新活动