What is the difference between surrounding the type with square brackets and surrounding the whole object

Issue

What is the difference between this code:

const userSchema = new Schema(
  {
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    password: { type: String, required: true },
    phoneNumber: { type: Number, required: false, unique: true },
    address: [{ type: mongoose.Types.ObjectID, required: true, ref: "Address" }],
  },
  {
    timestamps: true,
  }
);

And this code:

const userSchema = new Schema(
  {
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    password: { type: String, required: true },
    phoneNumber: { type: Number, required: false, unique: true },
    address: { type: [mongoose.Types.ObjectID], required: true, ref: "Address" },
  },
  {
    timestamps: true,
  }
);

NOTICE:

  • In the first code, I surrounded the whole address object with square brackets.
  • In the second code, I only surrounded the type property of the address with square brackets.

What I want to know is how that will impact the app’s behavior.
Is there any difference?

Thanks.

Solution

They both declare an array-of-references, but there are some subtle differences.

Let’s take this simple schema:

const userSchema = mongoose.Schema({
  address: { type: [ String ], required: true, default: undefined }
});
const User = mongoose.model('User', userSchema);

This will apply the options (required and default) to the address array-of-strings as a whole:

// This will fail validation:
//   ValidatorError: Path `address` is required
const doc = new User({});

// This will pass validation:
const doc = new User({ address : [] });

Now change the position of the brackets in the schema:

const userSchema = mongoose.Schema({
  address: [{ type: String, required: true, default: undefined }]
});

This will apply the options to the elements of the address array:

// This will pass validation, `address` itself isn't required:
const user = new User({});
// This will also pass validation, for the same reason:
const user = new User({ address : [] });
// This will fail validation, because elements of the array are required to have a proper value
// ValidatorError: Path `address.0` is required
const user = new User({ address : [ '' ] });

EDIT: if you want to enforce that the address field is always defined and has at least one element, you have to use a custom validator. For your schema, it would look like this:

address: { 
  type:     [ mongoose.Schema.Types.ObjectID ],
  ref:      'Address',
  required: true,
  default:  undefined,
  validate: a => Array.isArray(a) && a.length > 0
}

Answered By – robertklep

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published