szokodiakos / typegoose

Typegoose - Define Mongoose models using TypeScript classes.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

arrayProp of ObjectId error

nllahat opened this issue · comments

Versions

  • NodeJS: 8.8.1
  • Typegoose(NPM): 5.8.0
  • mongoose: 5.4.23
  • mongodb: 3.4

Code Example

@arrayProp({ items: Types.ObjectId })
  public classifications?: Types.ObjectId[]

Do you know why it happenes?

Because in Typegoose version ~5.8.0 and ~5.9.0 the array of objectIds really sent as Array type to the mongoose schema function interpretAsType (mongoose/lib/schema.js) and it triggers this code (the error of Invalid schema configuration is thrown):

if (Array.isArray(type) || Array === type || type === 'array') {
    // if it was specified through { type } look for `cast`
    let cast = (Array === type || type === 'array')
      ? obj.cast
      : type[0];

    if (cast && cast.instanceOfSchema) {
      return new MongooseTypes.DocumentArray(path, cast, obj);
    }
    if (cast &&
        cast[options.typeKey] &&
        cast[options.typeKey].instanceOfSchema) {
      return new MongooseTypes.DocumentArray(path, cast[options.typeKey], obj, cast);
    }

    if (Array.isArray(cast)) {
      return new MongooseTypes.Array(path, this.interpretAsType(path, cast, options), obj);
    }

    if (typeof cast === 'string') {
      cast = MongooseTypes[cast.charAt(0).toUpperCase() + cast.substring(1)];
    } else if (cast && (!cast[options.typeKey] || (options.typeKey === 'type' && cast.type.type))
        && utils.isPOJO(cast)) {
      if (Object.keys(cast).length) {
        // The `minimize` and `typeKey` options propagate to child schemas
        // declared inline, like `{ arr: [{ val: { $type: String } }] }`.
        // See gh-3560
        const childSchemaOptions = {minimize: options.minimize};
        if (options.typeKey) {
          childSchemaOptions.typeKey = options.typeKey;
        }
        //propagate 'strict' option to child schema
        if (options.hasOwnProperty('strict')) {
          childSchemaOptions.strict = options.strict;
        }
        const childSchema = new Schema(cast, childSchemaOptions);
        childSchema.$implicitlyCreated = true;
        return new MongooseTypes.DocumentArray(path, childSchema, obj);
      } else {
        // Special case: empty object becomes mixed
        return new MongooseTypes.Array(path, MongooseTypes.Mixed, obj);
      }
    }

    if (cast) {
      type = cast[options.typeKey] && (options.typeKey !== 'type' || !cast.type.type)
        ? cast[options.typeKey]
        : cast;

      name = typeof type === 'string'
        ? type
        : type.schemaName || utils.getFunctionName(type);

      if (!(name in MongooseTypes)) {
        throw new TypeError('Invalid schema configuration: ' +
          `\`${name}\` is not a valid type within the array \`${path}\`.` +
          'See http://bit.ly/mongoose-schematypes for a list of valid schema types.');
      }
    }

    return new MongooseTypes.Array(path, cast || MongooseTypes.Mixed, obj, options);
  }

In the old version of Typegoose (5.7.2) the property type is not sent as Array and the mongoose code is triggered:

// Special case re: gh-7049 because the bson `ObjectID` class' capitalization
  // doesn't line up with Mongoose's.
  if (name === 'ObjectID') {
    name = 'ObjectId';
  }

and that's why I don't get this error below

The Error

TypeError: Invalid schema configuration: ObjectID is not a valid type within the array classifications.See http://bit.ly/mongoose-schematypes for a list of valid schema types.

mongoose: 5.4.23

in typegoose 5.9.0+ it needs mongoose 5.6.7+
(just pointing it out)


and you are sure you dont want to use ref for this?


i looked into the source code, and between release 5.7.2 and 5.9.0, nothing has changed how the array is handled, only the mongoose version has changed


could confirm that it errors out, but as already stated, since version 5.7.2 nothing at array handling has changed...

import * as mongoose from "mongoose";
import "source-map-support/register";
import { arrayProp, prop, Typegoose } from "./typegoose/src/typegoose";

class Dummy extends Typegoose {
    @prop({ required: true })
    public doc?: mongoose.Types.ObjectId;
}

class DummyArray extends Typegoose {
    @arrayProp({ required: true, items: mongoose.Types.ObjectId })
    public docs?: mongoose.Types.ObjectId[];
}

const DummyModel = new Dummy().getModelForClass(Dummy);
const DummyArrayModel = new DummyArray().getModelForClass(DummyArray);

(async () => {
    mongoose.set("debug", true);
    await mongoose.connect(`mongodb://mongodb:27017/`, {
        useNewUrlParser: true,
        useFindAndModify: true,
        useCreateIndex: true,
        dbName: "verify362",
        user: "user",
        pass: "passwd",
        authSource: "admin",
        autoIndex: true
    });

    const doc = new DummyModel({ doc: new mongoose.Types.ObjectId() });
    await doc.save();
    console.log(doc.toObject());

    const docs = new DummyArrayModel({ docs: [new mongoose.Types.ObjectId(), new mongoose.Types.ObjectId(), new mongoose.Types.ObjectId()] });
    await docs.save();
    console.log(docs.toObject());

    await mongoose.disconnect();
})();

found the error, its not an error with typegoose, but i could fix it in typegoose

description of the error:
the type mongoose.Types.ObjectId has Type.name of ObjectID, but mongoose expects ObjectId, will implement a workaround soon

made an mongoose issue Automattic/mongoose#8034

(please dont close this issue until the mongoose issue is fixed)

in typegoose 5.9.0+ it needs mongoose 5.6.7+
(just pointing it out)

Thanks. Will check if it is possible for us to upgrade.

and you are sure you dont want to use ref for this?

Those objectIds are from another microservice in other db. so ref won't fit.

Thanks for helping. Waiting for the mongoose fix (:

Those objectIds are from another microservice in other db. so ref won't fit.

just wanted to confirm that it didnt got overseen, because that happened already :)

the temporary fix #363 got merged, but still waiting on mongoose to fix it on their side

@hasezoey still getting this error on ^5.9.0

error TS2352: Conversion of type 'Ref<User>' to type 'ObjectId' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'User' is missing the following properties from type 'ObjectId': generationTime, equals, getTimestamp, toHexString

I believe its related to this ObjectId vs ObjectID right?

@ChrisLahaye, yes it got merged long ago, but since then @Ben305 has not made a new version, so it was never in a version yet, but it got fixed my mongoose itself now (i dont know the version anymore)

PS: as of version 5.9.1 it got released

@hasezoey can you update your fork to mongoose 5.6.9 such that mongoose exports ObjectID (which I believe is used in the union type Ref)

@ChrisLahaye typegoose v6.0.0 uses 5.7, after arrayvalidators get merged

but v5.x will not get and updated mongoose, otherwise, it works with every mongoose, because it is a peer dependency

@Ben305 this can be closed as "fixed" - in version 5.9.1

@Ben305 Bump to close