npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ladjs/mongoose-unique-validator

v5.0.0

Published

Mongoose plugin which adds pre-save validation for unique fields within a Mongoose schema. This makes error handling much easier, since you will get a Mongoose validation error when you attempt to violate a unique constraint, rather than an E11000 error f

Downloads

184

Readme

@ladjs/mongoose-unique-validator

build status code style styled with prettier made with lass license

Mongoose plugin which adds pre-save validation for unique fields within a Mongoose schema. This makes error handling much easier, since you will get a Mongoose validation error when you attempt to violate a unique constraint, rather than an E11000 error from MongoDB. Fork of the original unmaintained package.

NOTE: As of v5.0.0+ if the only unique index is _id, then E11000 will be thrown by default. This prevents an unnecessary call to countDocuments and is a major optimization.

Table of Contents

Install

npm:

npm install @ladjs/mongoose-unique-validator

Usage

const mongoose = require('mongoose');
const uniqueValidator = require('@ladjs/mongoose-unique-validator');

const mySchema = mongoose.Schema({
  // TODO: put your schema definition here
});

// NOTE: this should come after any indexes are added to your schema (incl from other plugins)
mySchema.plugin(uniqueValidator);

Example

Let's say you have a user schema. You can easily add validation for the unique constraints in this schema by applying the uniqueValidator plugin to your user schema:

const mongoose = require('mongoose');
const uniqueValidator = require('@ladjs/mongoose-unique-validator');

// Define your schema as normal.
const userSchema = mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: { type: String, index: true, unique: true, required: true },
  password: { type: String, required: true }
});

// Apply the uniqueValidator plugin to userSchema.
userSchema.plugin(uniqueValidator);

Now when you try to save a user, the unique validator will check for duplicate database entries and report them just like any other validation error:

const user = new User({ username: 'JohnSmith', email: '[email protected]', password: 'j0hnNYb0i' });
await user.save();
{
  message: 'Validation failed',
  name: 'ValidationError',
  errors: {
    username: {
      message: 'Error, expected `username` to be unique. Value: `JohnSmith`',
      name: 'ValidatorError',
      kind: 'unique',
      path: 'username',
      value: 'JohnSmith'
    }
  }
}

Find + Updates

When using findOneAndUpdate and related methods, mongoose doesn't automatically run validation. To trigger this, you need to pass a configuration object. For technical reasons, this plugin requires that you also set the context option to query.

{ runValidators: true, context: 'query' }

A full example:

await User.findOneAndUpdate(
  { email: '[email protected]' },
  { email: '[email protected]' },
  { runValidators: true, context: 'query' }
);

Custom Error Types

You can pass through a custom error type as part of the optional options argument:

userSchema.plugin(uniqueValidator, { type: 'mongoose-unique-validator' });

After running the above example the output will be:

{
  message: 'Validation failed',
  name: 'ValidationError',
  errors: {
    username: {
      message: 'Error, expected `username` to be unique. Value: `JohnSmith`',
      name: 'ValidatorError',
      kind: 'mongoose-unique-validator',
      path: 'username',
      value: 'JohnSmith'
    }
  }
}

You can also specify a default custom error type by overriding the plugin defaults.type variable:

uniqueValidator.defaults.type = 'mongoose-unique-validator'

Custom Error Messages

You can pass through a custom error message as part of the optional options argument:

userSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });

You have access to all of the standard Mongoose error message templating:

  • {PATH}
  • {VALUE}
  • {TYPE}

You can also specify a default custom error message by overriding the plugin defaults.message variable:

uniqueValidator.defaults.message = 'Error, expected {PATH} to be unique.'

Case Insensitive

For case-insensitive matches, include the uniqueCaseInsensitive option in your schema. Queries will treat [email protected] and [email protected] as duplicates.

const userSchema = mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true },
  password: { type: String, required: true }
});

Additional Conditions

For additional unique-constraint conditions (ex: only enforce unique constraint on non soft-deleted records), the MongoDB option partialFilterExpression can be used.

Note: the option index must be passed as an object containing unique: true, or else partialFilterExpression will be ignored.

const userSchema = mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: {
    type: String,
    required: true,
    index: {
      unique: true,
      partialFilterExpression: { deleted: false }
    }
  },
  password: { type: String, required: true }
});

Caveats

Because we rely on async operations to verify whether a document exists in the database, it's possible for two queries to execute at the same time, both get 0 back, and then both insert into MongoDB.

Outside of automatically locking the collection or forcing a single connection, there's no real solution.

For most of our users this won't be a problem, but is an edge case to be aware of.

Contributors

| Name | | --------------- | | Mike Botsko |

License

MIT © Blake Haswell