CargoMeister
CargoMeister

Reputation: 4299

Does Mongoose Actually Validate the Existence of An Object Id?

I like the validation that comes with Mongoose. We are trying to figure out whether we want to use it, and put up with the overhead. Does anyone know if providing a reference to the parent collection when creating a mongoose schema, (in the child schema, specify the object id of the parent object as a field,) does this then mean that every time you try to save the document it checks the parent collection for the existence of the refereneced object id?

Upvotes: 20

Views: 14775

Answers (6)

avivyar
avivyar

Reputation: 51

I know this is an old thread but I had the same problem and I came up with a more "modern" solution. I'm not an expert myself, hope I'm not misleading anyone, but this seems to work:

for example, in a simple "notes" schema, which contains a user field:

const noteSchema = new Schema({
  user: { type: Schema.Types.ObjectId, ref: 'User' },
  text: String
});

here's the middleware that checks if the userId exists:

noteSchema.path('user').validate(async (value) => {
  return await User.findById(value);
}, 'User does not exist');

Upvotes: 2

Avi E. Koenig
Avi E. Koenig

Reputation: 379

I found this thread very helpful and this is what I came up with:

This Middleware (I think its one anyway please let me know if not) I wrote checks the referenced model for the id provided in the field.

const mongoose = require('mongoose');

module.exports = (value, respond, modelName) => {
    return modelName
        .countDocuments({ _id: value })
        .exec()
        .then(function(count) {
            return count > 0;
        })
        .catch(function(err) {
            throw err;
        });
}; 

Example model:

const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const Schema = mongoose.Schema;
const User = require('./User');
const Cart = require('./Cart');
const refIsValid = require('../middleware/refIsValid');

const orderSchema = new Schema({
    name: { type: String, default: Date.now, unique: true },
    customerRef: { type: Schema.Types.ObjectId, required: true },
    cartRef: { type: Schema.Types.ObjectId, ref: 'Cart', required: true },
    total: { type: Number, default: 0 },
    city: { type: String, required: true },
    street: { type: String, required: true },
    deliveryDate: { type: Date, required: true },
    dateCreated: { type: Date, default: Date.now() },
    ccLastDigits: { type: String, required: true },
});

orderSchema.path('customerRef').validate((value, respond) => {
    return refIsValid(value, respond, User);
}, 'Invalid customerRef.');

orderSchema.path('cartRef').validate((value, respond) => {
    return refIsValid(value, respond, Cart);
}, 'Invalid cartRef.');

orderSchema.path('ccLastDigits').validate(function(field) {
    return field && field.length === 4;
}, 'Invalid ccLastDigits: must be 4 characters');

orderSchema.plugin(uniqueValidator);

module.exports = mongoose.model('order', orderSchema);

I'm a very new dev so any feedback is greatly valued!

Upvotes: 2

Tiago Relvao
Tiago Relvao

Reputation: 66

You can try https://www.npmjs.com/package/lackey-mongoose-ref-validator (I'm the developer)

It also prevents deletion if the reference is used on another document.

var mongooseRefValidator = require('lackey-mongoose-ref-validator');
mongoSchema.plugin(mongooseRefValidator, {
    onDeleteRestrict: ['tags']
});

It's an early version, so some bugs are expected. Just fill in a ticket if you find any.

Upvotes: 1

Amit Portnoy
Amit Portnoy

Reputation: 6336

I'm using mongoose-id-validator. Works good

var mongoose = require('mongoose');
var idValidator = require('mongoose-id-validator');

var ReferencedModel = new mongoose.Schema({name: String});

var MySchema = new mongoose.Schema({
  referencedObj : { type: mongoose.Schema.Types.ObjectId, ref: 'ReferencedModel'},
  referencedObjArray: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ReferencedModel' }]
});

MySchema.plugin(idValidator);

Upvotes: 18

fernandopasik
fernandopasik

Reputation: 10453

I'm doing it with middleware, performing a search of the element on validation:

ExampleSchema = new mongoose.Schema({

    parentId: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Example'
    }

});

ExampleModel = mongoose.model('Example', ExampleSchema);

ExampleSchema.path('parentId').validate(function (value, respond) {

    ExampleModel.findOne({_id: value}, function (err, doc) {
        if (err || !doc) {
            respond(false);
        } else {
            respond(true);
        }
    });

}, 'Example non existent');

Upvotes: 23

JohnnyHK
JohnnyHK

Reputation: 311865

No, an ObjectId field that's defined in your schema as a reference to another collection is not checked as existing in the referenced collection on a save. You could do it in Mongoose middleware, if needed.

Upvotes: 3

Related Questions