阿里云主机折上折
  • 微信号
Current Site:Index > Data types and field validation

Data types and field validation

Author:Chuan Chen 阅读数:21957人阅读 分类: MongoDB

Data Type Basics

Mongoose provides a variety of data types for defining model fields. The most commonly used basic types include:

  • String: String type
  • Number: Numeric type
  • Date: Date type
  • Boolean: Boolean type
  • Buffer: Binary data type
  • ObjectId: MongoDB document ID
  • Array: Array type
  • Mixed: Mixed type
const userSchema = new mongoose.Schema({
  name: String,
  age: Number,
  isActive: Boolean,
  createdAt: Date,
  hobbies: Array,
  profile: Object
});

Field Validation Mechanism

Mongoose validators automatically execute before saving documents. Built-in validators include:

  1. required: Required field validation
  2. min/max: Numeric range validation
  3. enum: Enum value validation
  4. match: Regex matching validation
  5. validate: Custom validation function
const productSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    minlength: 3,
    maxlength: 50
  },
  price: {
    type: Number,
    min: 0,
    max: 10000
  },
  category: {
    type: String,
    enum: ['electronics', 'clothing', 'food']
  }
});

Custom Validators

More complex validation logic can be defined using the validate property:

const userSchema = new mongoose.Schema({
  email: {
    type: String,
    validate: {
      validator: function(v) {
        return /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(v);
      },
      message: props => `${props.value} is not a valid email address`
    }
  },
  age: {
    type: Number,
    validate: {
      validator: function(v) {
        return v >= 18 && v <= 120;
      },
      message: 'Age must be between 18 and 120'
    }
  }
});

Asynchronous Validation

For validations requiring asynchronous operations, return a Promise:

const usernameSchema = new mongoose.Schema({
  username: {
    type: String,
    validate: {
      validator: function(v) {
        return new Promise((resolve, reject) => {
          User.findOne({ username: v })
            .then(user => resolve(!user))
            .catch(err => reject(err));
        });
      },
      message: 'Username already exists'
    }
  }
});

Nested Object Validation

Validation rules can also be applied to nested objects:

const addressSchema = new mongoose.Schema({
  street: { type: String, required: true },
  city: { type: String, required: true },
  zipCode: {
    type: String,
    validate: {
      validator: function(v) {
        return /^\d{5}(-\d{4})?$/.test(v);
      }
    }
  }
});

const customerSchema = new mongoose.Schema({
  name: String,
  address: addressSchema
});

Array Validation

Array fields can validate element types and quantities:

const postSchema = new mongoose.Schema({
  tags: {
    type: [String],
    validate: {
      validator: function(v) {
        return v.length > 0 && v.length <= 5;
      },
      message: 'Number of tags must be between 1 and 5'
    }
  },
  comments: [{
    text: String,
    author: String,
    createdAt: { type: Date, default: Date.now }
  }]
});

Error Handling

Validation failures throw ValidationError, which can be caught and handled:

const newUser = new User({ email: 'invalid-email' });

newUser.save()
  .then(doc => console.log(doc))
  .catch(err => {
    if (err instanceof mongoose.Error.ValidationError) {
      console.error('Validation error:', err.errors);
    } else {
      console.error('Other error:', err);
    }
  });

Custom Error Messages

Custom error messages can be specified for each validation type:

const bookSchema = new mongoose.Schema({
  title: {
    type: String,
    required: [true, 'Title cannot be empty'],
    minlength: [3, 'Title must be at least 3 characters'],
    maxlength: [100, 'Title cannot exceed 100 characters']
  },
  isbn: {
    type: String,
    match: [/^\d{3}-\d{10}$/, 'ISBN format should be XXX-XXXXXXXXXX']
  }
});

Conditional Validation

Some field validations may depend on other field values:

const orderSchema = new mongoose.Schema({
  paymentMethod: {
    type: String,
    enum: ['credit', 'paypal', 'bank']
  },
  creditCardNumber: {
    type: String,
    validate: {
      validator: function(v) {
        return this.paymentMethod !== 'credit' || 
              /^\d{16}$/.test(v);
      },
      message: 'Credit card payment requires a 16-digit card number'
    }
  }
});

Validation Middleware

Use pre hooks to perform additional validation before saving:

userSchema.pre('save', function(next) {
  if (this.isModified('password') && this.password.length < 8) {
    throw new Error('Password must be at least 8 characters');
  }
  next();
});

Disabling Validation

Validation can be skipped in certain cases:

// Skip all validation
doc.save({ validateBeforeSave: false });

// Skip validation for specific paths
doc.save({ validateModifiedOnly: true });

Custom Types

Custom SchemaType extensions can be created:

class TruncateString extends mongoose.SchemaType {
  constructor(key, options) {
    super(key, options, 'TruncateString');
    this.maxLength = options.maxLength || 100;
  }

  cast(val) {
    let _val = String(val);
    if (_val.length > this.maxLength) {
      _val = _val.substring(0, this.maxLength);
    }
    return _val;
  }
}

mongoose.Schema.Types.TruncateString = TruncateString;

const schema = new mongoose.Schema({
  excerpt: { type: TruncateString, maxLength: 50 }
});

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.