Search code examples
node.jsmongodbtypescriptmongoosemongoose-schema

How to define non-required field in Mongoose schema with nested "type" property?


I have the following Mongoose schema definition in my project:

export const ProductSchema: SchemaDefinition = {
  type: { type: String, enum: constants.productTypes, required: true },
  name: { type: String, required: false },

  espData: {
    type: { type: String, required: true },
    text: { type: String, required: true }
  },

  error: {
    type: {
      message: { type: String, required: true },
      statusCode: { type: Number, default: null }
    },
    required: false
  }
  // Some more definitions...
};

What's important from here is that I have collection of products where each product has its own type (which is a required string property that can have values defined in constants.productTypes), a non-required name field and so on. Also, there's espData field that has its own mandatory type property which is completely different from the top level type. And, there's error property that does not exist at all times, but when it does, it must have message property and optional statusCode property.

I now have to modify this schema so that espData becomes optional field since I may now have products that don't have this property. How do I do that? I tried couple of things, but none of them worked:

  • First, I modified espData so that it looks the same as error:
  espData: {
    type: {
      type: { type: String, required: true },
      text: { type: String, required: true }
    },
    required: false
  },

But, this is not working, most probably because there's so many nested type properties. Funny thing is that it perfectly works for the error property which has the same structure as espData, but without nested type property. The code I used is

    const model = new this.factories.product.model();
    model.type = 'hi-iq';
    // model.espData purposely left undefined
    await model.save();

The error I'm getting is Product validation failed: espData.type.text: Path 'espData.type.text' is required., espData.type.type: Path 'espData.type.type' is required. This indicates that model created from schema is created as espData.type.type which is not what I wanted (I wanted espData.type).

  • Second, I have tried the same from above, just instead of required field, I wrote: default: null which gave me an error TypeError: Invalid value for schema path 'espData.default', got value "null".

So, how do I define espData as an optional field, which must have type and text properties when it exists?


Solution

  • Is this what you want. Create a new Document Schema with all the validations and nest it in another Schema with required: false (its default to false anyway)

    const EspDataSchema = new Schema({
      type: { type: String, required: true },
      text: { type: String, required: true },
    },
      {
        _id: false,
      }
    
    );
    

    example

    
    export const ProductSchema = new Schema({
    
    ...
       espData: {
        type: EspDataSchema,
        required: false
       },
    
    ...
    
    })