Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail to update subSchema documentArray Error parentArray.getArrayParent is not a function #12518

Closed
2 tasks done
abarriel opened this issue Oct 4, 2022 · 2 comments · Fixed by #12571
Closed
2 tasks done
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@abarriel
Copy link
Contributor

abarriel commented Oct 4, 2022

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

6.6.3

Node.js version

16

MongoDB server version

4.9.1

Description

Hello I cannot update an array in subSchema when runValidators is set to true, on schema with a discriminator.

node_modules/mongoose/lib/schema/documentarray.js:136
    if (parentArray == null || parentArray.getArrayParent() == null) {
                                           ^

TypeError: parentArray.getArrayParent is not a function

This is a working exemple

Steps to Reproduce

const mongoose = require("mongoose");

mongoose.set("strict", "throw");
mongoose.set("runValidators", true);

const options = { discriminatorKey: "kind" };

const countrySchema = new mongoose.Schema({ title: String }, options);

const areasSubSchema = new mongoose.Schema(
  { country: [countrySchema] },
  options
);

const WorldSchema = new mongoose.Schema(
  {
    areas: areasSubSchema,
  },
  options
);

const World = mongoose.model(
  "World",
  new mongoose.Schema({ title: String }, options)
);
const Earth = World.discriminator("Earth", WorldSchema);

async function main() {
  await mongoose.connect("mongodb://localhost:27017");

  const data = {
    areas: {
      country: [
        {
          title: "titlec",
        },
      ],
    },
  };
  const eventDoc = await Earth.findByIdAndUpdate(
    { _id: mongoose.Types.ObjectId() },
    data,
    {
      new: true,
    }
  );

  console.log(eventDoc);
}

main();

Expected Behavior

No response

@abarriel abarriel changed the title Fail to update documentArray parentArray.getArrayParent is not a function Fail to update subSchema documentArray Error parentArray.getArrayParent is not a function Oct 4, 2022
@hasezoey
Copy link
Collaborator

hasezoey commented Oct 5, 2022

can reproduce

Code used
// NodeJS: 18.8.0
// MongoDB: 5.0 (Docker)
// Typescript 4.8.4
import * as mongoose from 'mongoose'; // mongoose@6.6.4

mongoose.set('runValidators', true); // without this option it does not occur

const countrySchema = new mongoose.Schema({ title: String });

const areasSubSchema = new mongoose.Schema({ country: [countrySchema] });

const WorldSchema = new mongoose.Schema({
  areas: areasSubSchema,
});

const WorldModel = mongoose.model('World', new mongoose.Schema({ title: String }));
const EarthModel = WorldModel.discriminator('Earth', WorldSchema);

(async () => {
  await mongoose.connect(`mongodb://localhost:27017/`, {
    dbName: 'verifyMASTER',
  });

  const data = {
    areas: {
      country: [
        {
          title: 'titlec',
        },
      ],
    },
  };
  const eventDoc = await EarthModel.findByIdAndUpdate({ _id: new mongoose.Types.ObjectId() }, data);

  console.log(eventDoc);

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

Reproduction Repository / Branch: https://github.com/typegoose/typegoose-testing/tree/mongooseGh12518

Output
/mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/schema/documentarray.js:135
    if (parentArray == null || parentArray.getArrayParent() == null) {
                                           ^

TypeError: parentArray.getArrayParent is not a function
    at new EmbeddedDocument (/mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/schema/documentarray.js:135:44)
    at DocumentArrayPath.$embeddedSchemaType.doValidate (/mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/schema/documentarray.js:90:15)
    at /mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/helpers/updateValidators.js:126:22
    at module.exports (/mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/helpers/updateValidators.js:202:7)
    at /mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/query.js:4314:9
    at promiseOrCallback (/mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/helpers/promiseOrCallback.js:11:14)
    at model.Query.validate (/mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/query.js:4309:10)
    at /mnt/projects/nodejs/typegoose-testing/node_modules/kareem/index.js:426:25
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)

it works without errors when not setting mongoose.set('runValidators', true);

on further debugging it seems that function EmbeddedDocument (inside function _createConstructor) gets called with a parentArray type of Query, which does not have a getArrayParent function

Full output of logging the parentArray type
PARENTARRAY Query {
  _mongooseOptions: {},
  _transforms: [],
  _hooks: Kareem { _pres: Map(0) {}, _posts: Map(0) {} },
  _executionStack: Error
      at model.Query._wrappedThunk [as _findOneAndUpdate] (/mnt/projects/nodejs/typegoose-testing/node_modules/mongoose/lib/helpers/query/wrapThunk.js:27:28)
      at /mnt/projects/nodejs/typegoose-testing/node_modules/kareem/index.js:426:25
      at process.processTicksAndRejections (node:internal/process/task_queues:77:11),
  mongooseCollection: Collection {
    collection: Collection { s: [Object] },
    Promise: [Function: Promise],
    modelName: 'World',
    _closed: false,
    opts: {
      autoIndex: true,
      autoCreate: true,
      schemaUserProvidedOptions: {},
      capped: false,
      Promise: [Function: Promise],
      '$wasForceClosed': undefined
    },
    name: 'worlds',
    collectionName: 'worlds',
    conn: NativeConnection {
      base: [Mongoose],
      collections: [Object],
      models: [Object],
      config: {},
      replica: false,
      options: null,
      otherDbs: [],
      relatedDbs: {},
      states: [Object: null prototype],
      _readyState: 1,
      _closeCalled: undefined,
      _hasOpened: true,
      plugins: [],
      id: 0,
      _queue: [],
      _listening: false,
      _connectionString: 'mongodb://localhost:27017/',
      _connectionOptions: [Object],
      '$dbName': 'verifyMASTER',
      client: [MongoClient],
      '$initialConnection': [Promise],
      db: [Db],
      host: 'localhost',
      port: 27017,
      name: 'verifyMASTER'
    },
    queue: [],
    buffer: false,
    emitter: EventEmitter {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      [Symbol(kCapture)]: false
    }
  },
  model: Model { Earth },
  schema: Schema {
    obj: { areas: [Schema], title: [Function: String] },
    paths: {
      areas: [SubdocumentPath],
      _id: [ObjectId],
      title: [SchemaString],
      __v: [SchemaNumber],
      __t: [SchemaString]
    },
    aliases: {},
    subpaths: {
      'areas.country.0': [SchemaType],
      'areas.country.0.title': [SchemaString],
      'areas.country.0._id': [ObjectId]
    },
    virtuals: { id: [VirtualType] },
    singleNestedPaths: {
      'areas.country': [DocumentArrayPath],
      'areas._id': [ObjectId],
      'areas.country.title': [SchemaString],
      'areas.country._id': [ObjectId]
    },
    nested: {},
    inherits: {},
    callQueue: [],
    _indexes: [],
    methods: {},
    methodOptions: {},
    statics: {},
    tree: {
      areas: [Schema],
      _id: [Object],
      title: [Function: String],
      __v: [Function: Number],
      id: [VirtualType],
      __t: [Object]
    },
    query: {},
    childSchemas: [ [Object] ],
    plugins: [ [Object], [Object], [Object], [Object], [Object] ],
    '$id': 6,
    mapPaths: [],
    s: { hooks: [Kareem] },
    _userProvidedOptions: {},
    options: {
      typeKey: 'type',
      id: true,
      _id: true,
      validateBeforeSave: true,
      read: null,
      shardKey: null,
      discriminatorKey: '__t',
      autoIndex: null,
      minimize: true,
      optimisticConcurrency: false,
      versionKey: '__v',
      capped: false,
      bufferCommands: true,
      strictQuery: true,
      strict: true,
      pluralization: true
    },
    base: <ref *1> Mongoose {
      connections: [Array],
      models: [Object],
      events: [EventEmitter],
      __driver: [Object],
      options: [Object],
      _pluralize: [Function: pluralize],
      Schema: [Function],
      model: [Function (anonymous)],
      plugins: [Array],
      default: [Circular *1],
      mongoose: [Circular *1],
      cast: [Function: cast],
      STATES: [Object: null prototype],
      setDriver: [Function: setDriver],
      set: [Function (anonymous)],
      get: [Function (anonymous)],
      createConnection: [Function (anonymous)],
      connect: [Function (anonymous)],
      disconnect: [Function (anonymous)],
      startSession: [Function (anonymous)],
      pluralize: [Function (anonymous)],
      deleteModel: [Function (anonymous)],
      modelNames: [Function (anonymous)],
      plugin: [Function (anonymous)],
      version: '6.6.4',
      Mongoose: [Function: Mongoose],
      SchemaType: [Function],
      SchemaTypes: [Object],
      VirtualType: [Function: VirtualType],
      Types: [Object],
      Query: [Function],
      Model: Model { undefined },
      Document: [Function],
      ObjectId: [Function],
      isValidObjectId: [Function (anonymous)],
      isObjectIdOrHexString: [Function (anonymous)],
      syncIndexes: [Function (anonymous)],
      Decimal128: [Function],
      Mixed: [Function],
      Date: [Function],
      Number: [Function],
      Error: [Function],
      now: [Function: now],
      CastError: [class CastError extends MongooseError],
      SchemaTypeOptions: [class SchemaTypeOptions],
      mongo: [Object],
      mquery: [Function],
      sanitizeFilter: [Function: sanitizeFilter],
      trusted: [Function: trusted],
      skipMiddlewareFunction: [Function: skipWrappedFunction],
      overwriteMiddlewareResult: [Function: overwriteResult]
    },
    '$globalPluginsApplied': true,
    '$isRootDiscriminator': true,
    '$implicitlyCreated': undefined,
    '$originalSchemaId': 3,
    _events: [Object: null prototype] { init: [Function (anonymous)] },
    _eventsCount: 1,
    _baseSchema: Schema {
      obj: [Object],
      paths: [Object],
      aliases: {},
      subpaths: {},
      virtuals: [Object],
      singleNestedPaths: {},
      nested: {},
      inherits: {},
      callQueue: [],
      _indexes: [],
      methods: {},
      methodOptions: {},
      statics: {},
      tree: [Object],
      query: {},
      childSchemas: [],
      plugins: [Array],
      '$id': 4,
      mapPaths: [],
      s: [Object],
      _userProvidedOptions: {},
      options: [Object],
      '$globalPluginsApplied': true,
      discriminatorMapping: [Object],
      discriminators: [Object]
    },
    discriminatorMapping: { key: '__t', value: 'Earth', isRoot: false },
    '$connectionPluginsApplied': true
  },
  op: 'findOneAndUpdate',
  options: {},
  _conditions: { __t: 'Earth', _id: new ObjectId("633d36c35a1effd83c51c31b") },
  _fields: {},
  _update: { '$set': { areas: [Object] } },
  _path: undefined,
  _distinct: undefined,
  _collection: NodeCollection {
    collection: Collection {
      collection: [Collection],
      Promise: [Function: Promise],
      modelName: 'World',
      _closed: false,
      opts: [Object],
      name: 'worlds',
      collectionName: 'worlds',
      conn: [NativeConnection],
      queue: [],
      buffer: false,
      emitter: [EventEmitter]
    },
    collectionName: 'worlds'
  },
  _traceFunction: undefined,
  '$useProjection': true
}

@hasezoey hasezoey added the confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. label Oct 5, 2022
@vkarpov15 vkarpov15 added this to the 6.6.6 milestone Oct 5, 2022
@andersondanilo
Copy link

I noticed that this bug was introduced in the version 6.4.0

vkarpov15 added a commit that referenced this issue Oct 19, 2022
vkarpov15 added a commit that referenced this issue Oct 20, 2022
fix(update): handle runValidators when using `$set` on a doc array in discriminator schema
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
4 participants