Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
26.96k stars 3.84k forks source link

"this.$__schema.paths[p].splitPath is not a function" when defining a document array using a schema from an earlier version of Mongoose #10453

Closed lucaslimao closed 2 years ago

lucaslimao commented 3 years ago

Do you want to request a feature or report a bug? Yes.

What is the current behavior?

I updated the lib version recently. from 5.9.4 to 5.13.2 After updated I run the code, I get the following error: this.$__schema.paths[p].splitPath is not a function started.

If the current behavior is a bug, please provide the steps to reproduce.

code snippet

    const follower = { id: value, ...user }

    const Model = new model

    Model.followers.push(follower)

**or**

const { nModified } = await model.update(
        { user: id, 'followers.id': { $ne: follower.id } },
        {
            $push: { followers: follower },
            $inc: { count: 1 }
        }
    )

**Schema**

const mongoose = require('mongoose')
const Schema = mongoose.Schema

const User = new Schema(
    {
        name: String
    },
    {
        _id: false,
        timestamps: true
    }
)

module.exports = {
    count: {
        type: Schema.Types.Number,
        default: 0
    },
    user: {
        type: Schema.Types.ObjectId, ref: 'User'
    },
    followers: [
        User
    ]
}

**Error**

{
    "errorMessage": "this.$__schema.paths[p].splitPath is not a function",
    "errorType": "TypeError",
    "stackTrace": [
        "TypeError: this.$__schema.paths[p].splitPath is not a function",
        "    at EmbeddedDocument.Document.$__buildDoc (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/document.js:490:42)",
        "    at EmbeddedDocument.Document (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/document.js:133:10)",
        "    at EmbeddedDocument [as constructor] (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/types/embedded.js:47:12)",
        "    at new EmbeddedDocument (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/schema/documentarray.js:116:17)",
        "    at CoreDocumentArray._cast (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/types/documentarray.js:109:12)",
        "    at CoreDocumentArray._mapCast (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/types/core_array.js:272:17)",
        "    at Arguments.map (<anonymous>)",
        "    at CoreDocumentArray.push (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/types/core_array.js:666:21)",
        "    at CoreDocumentArray.push (/home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository/node_modules/mongoose/lib/types/documentarray.js:210:28)",
        "    at Object.add (/home/lucas/dev/users-service/workers/utils/handler.bucket.js:49:21)",
        "    at processTicksAndRejections (internal/process/task_queues.js:97:5)",
        "    at async Object.create (/home/lucas/dev/users-service/workers/services/followers/command/index.js:17:28)",
        "    at async /home/lucas/dev/users-service/workers/handler.followers.js:46:13",
        "    at async Promise.all (index 0)",
        "    at async create (/home/lucas/dev/users-service/workers/handler.followers.js:37:5)"
    ]
}

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.

Node.js 12.18.3 Mongoose 5.13.2 Mongo 4.4

IslandRhythms commented 3 years ago

Check that you do not have multiple versions of mongoose installed

lucaslimao commented 3 years ago

Hey @IslandRhythms . No, I don't have multiple versions of mongoose. I noticed that the error appears when using a new Schema, if I remove the new Schema, the error doesn't appear.

example:

const User = {
        name: String
}

module.exports = {
    count: {
        type: Schema.Types.Number,
        default: 0
    },
    user: {
        type: Schema.Types.ObjectId, ref: 'User'
    },
    followers: [
        User
    ]
}
vkarpov15 commented 3 years ago

@lucaslimao this does look indicative of having multiple versions of Mongoose installed. My best guess is that /home/lucas/dev/users-service/workers has a distinct version of Mongoose from /home/lucas/dev/users-service/workers/node_modules/node-mongoose-repository and that's what is causing the issue.

Can you please try running npm list mongoose and paste the output?

gregorybellencontre commented 2 years ago

Hello :) I have a weird error with Mongoose, based on the fix that has been made following this issue.

Schema for array path `credits` is from a different copy of the Mongoose module. Please make sure you're using the same version of Mongoose everywhere with `npm list mongoose`.

I'm using schemas defined in a different repository, both repositories have Mongoose 6.1.2 I checked the yarn.lock and node_modules to be 100% sure, and I only have one version of Mongoose.

After some tests with Mongoose, I figured out that I can solve the problem by removing this throw : https://github.com/Automattic/mongoose/blob/master/lib/schema.js#L952

I don't have any other error.

I would be interested to have your thoughts about this case.

const TitleSchema = new mongoose.Schema<Title>(
  {
    title: {
      type: String
    },
    credits: [CreditSchema]
  }
)
const CreditSchema = new mongoose.Schema<Credit>({
  personId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'persons',
    key: 'person',
    required: [true, 'ERROR_REQUIRED'],
  },
  jobId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'jobs',
    key: 'job',
    required: [true, 'ERROR_REQUIRED'],
  }
})

Thanks !

vkarpov15 commented 2 years ago

@gregorybellencontre can you please paste the output of npm list | grep "mongo" or whatever the yarn equivalent is?

gregorybellencontre commented 2 years ago

@vkarpov15 Here's the result of the yarn link | grep "mongo" :

│  ├─ mongodb@4.2.2
│  ├─ mongoose@6.1.3
├─ mongodb-connection-string-url@2.3.2
├─ mongodb@4.2.2
│  ├─ mongodb-connection-string-url@^2.3.2
├─ mongoose@6.1.3
│  ├─ mongodb@4.2.2
vkarpov15 commented 2 years ago

So you do have 2 copies of Mongoose after all, they're just the same version. Where does the nested version of mongoose come from?

gregorybellencontre commented 2 years ago

Indeed, I'm using a personal NPM package where I store some Mongoose schemas. So I had a copy of Mongoose in this NPM package + another copy in my main repository. I don't know how, but I finally managed to remove the mongoose copy from the node_modules of my schemas package. It's working fine now. Thanks for your help.

vkarpov15 commented 2 years ago

If you have an npm package that stores Mongoose schemas, we'd recommend listing Mongoose in peerDependencies.

mikkixlisa commented 2 years ago

I am facing the same issue but only when using the 'remote' schema in an Array.

I defined a Tag schema in a separate npm package:

export const TagSchemaDefinition: SchemaDefinition<SchemaDefinitionType<Tag>> = {
  color: String,
  name: { required: true, type: String },
  slug: { required: true, type: String },
};

export const TagSchema = new Schema<Tag>(TagSchemaDefinition, { _id: false });

When trying to use this schema in my main repo like this:

const SomeSchema = new Schema<SomeDocument, SomeModel>(
  {
    ...
    tags: [TagSchema],
    ...
  },
  { ... },
);

I am getting an error:

TypeError: Schema for array path `tags` is from a different copy of the Mongoose module. 
Please make sure you're using the same version of Mongoose everywhere with `npm list mongoose`.

When using it as a single item, it works fine:

const SomeSchema = new Schema<SomeDocument, SomeModel>(
  {
    ...
    tag: TagSchema,
    ...
  },
  { ... },
);

Output of npm list | grep "mongo":

├── @private/mongoose-shared@2.6.1
├── mongoose@6.1.5
└── uuid-mongodb@2.5.0

Output of npm list mongoose:

├─┬ @private/mongoose-shared@2.6.1
│ └── mongoose@6.1.5 deduped
└── mongoose@6.1.5

In @private/mongoose-shared I am listing mongoose as peerDependency.

sbland commented 2 years ago

I get this issue after updating from 5.12.3 to 5.13.14.
I only get the error when using jest. Output of npm list | grep "mongo"

@shelf/jest-mongodb@2.2.0
├── mongodb@3.7.3
├── mongoose@5.13.14

Edit: This seemed to be caused by manually setting the _id. This worked prior to mongoose@5.13 but from docs it looks like it should have failed.

const newDoc = new Model({ 
     _id: mongoose.Types.ObjectId('customid'),
});
const insertedDoc = await newDoc.save();
vkarpov15 commented 2 years ago

We'll try a different approach with 50b670c. Our approach of throwing an error if you pass something that isn't strictly instanceof Schema might be a bit too coarse. We'll instead use clone() to try to convert the schema instance to the calling Mongoose instance's Schema class.

As a workaround, you can always wrap your shared schema in a new Schema() call:

const SomeSchema = new Schema<SomeDocument, SomeModel>(
  {
    ...
    tags: [new Schema(TagSchema)],
    ...
  },
  { ... },
);

This should work, even if TagSchema is an instance of a different Mongoose module's Schema class.

vkarpov15 commented 2 years ago

On second thought, we're just going to improve the error message to suggest using new Schema() to correct the error. We don't want to necessarily always try to convert a schema from a potentially different version of Mongoose to the current version's implicitly. That could lead to surprising behavior. At least, with the error, devs will be aware of the issue, and hopefully check that new Schema(TagSchema) works as expected for them.