function SchemaDocumentArray(key, schema, options, schemaOptions) {
  if (schema.options && schema.options.timeseries) {
    throw new InvalidSchemaOptionError(key, 'timeseries');
  }
  const schemaTypeIdOption = SchemaDocumentArray.defaultOptions &&
    SchemaDocumentArray.defaultOptions._id;
  if (schemaTypeIdOption != null) {
    schemaOptions = schemaOptions || {};
    schemaOptions._id = schemaTypeIdOption;
  }

  if (schemaOptions != null && schemaOptions._id != null) {
    schema = handleIdOption(schema, schemaOptions);
  } else if (options != null && options._id != null) {
    schema = handleIdOption(schema, options);
  }

  const EmbeddedDocument = _createConstructor(schema, options);
  EmbeddedDocument.prototype.$basePath = key;

  SchemaArray.call(this, key, EmbeddedDocument, options);

  this.schema = schema;
  this.schemaOptions = schemaOptions || {};
  this.$isMongooseDocumentArray = true;
  this.Constructor = EmbeddedDocument;

  EmbeddedDocument.base = schema.base;

  const fn = this.defaultValue;

  if (!('defaultValue' in this) || fn != null) {
    this.default(function() {
      let arr = fn.call(this);
      if (arr != null && !Array.isArray(arr)) {
        arr = [arr];
      }
      // Leave it up to `cast()` to convert this to a documentarray
      return arr;
    });
  }

  const $parentSchemaType = this;
  this.$embeddedSchemaType = new DocumentArrayElement(key + '.$', {
    required: this &&
      this.schemaOptions &&
      this.schemaOptions.required || false,
    $parentSchemaType
  });

  this.$embeddedSchemaType.caster = this.Constructor;
  this.$embeddedSchemaType.schema = this.schema;
}
SubdocsArray SchemaType constructor

@param {String} key
@param {Schema} schema
@param {Object} options
@param {Object} schemaOptions
@inherits SchemaArray
@api public