admin管理员组文章数量:1302958
I'm building a Next.js application with TypeScript and MongoDB/Mongoose. I started running into an error when using Mongoose models, which was causing them to attempt an overwrite of the Model every time it was used.
Code causing Model Overwrite error:
import mongoose from 'mongoose';
const { Schema } = mongoose;
const categorySchema = new Schema({
name: {type: String, required: true},
color: {type: String, required: true}
})
export default mongoose.model('Category', categorySchema, 'categories')
I found that on many projects using Next.js and Mongoose, including the example project by Next.js, they used the following syntax on the export to fix this problem:
export default mongoose.models.Category || mongoose.model('Category', categorySchema, 'categories')
This feels pretty weird and "bandaid solution"-esque, but it seems to do the trick at first glance; it prevents an overwrite if the model already exists. However, using TypeScript I started running into another problem, which after some time I found was being caused by that very line. Since the export was finnicky, TypeScript couldn't parse the Category model, and threw errors whenever I tried to use most of its properties or methods. I looked deeper into it and found some other people going around this by doing:
import mongoose from 'mongoose';
const { Schema } = mongoose;
const categorySchema = new Schema({
name: {type: String, required: true},
color: {type: String, required: true}
})
interface CategoryFields {
name: string,
color: string
}
type CategoryDocument = mongoose.Document & CategoryFields
export default (mongoose.models.Category as mongoose.Model<CategoryDocument>) || mongoose.model('Category', categorySchema, 'categories')
Again, this seems to do the trick but it's merely tricking TypeScript into believing there's nothing weird going on, when in reality there is.
Is there no real solution to fix the Model Overwrite problem without jumping through hoops and covering errors with other errors?
Thanks in advance!
I'm building a Next.js application with TypeScript and MongoDB/Mongoose. I started running into an error when using Mongoose models, which was causing them to attempt an overwrite of the Model every time it was used.
Code causing Model Overwrite error:
import mongoose from 'mongoose';
const { Schema } = mongoose;
const categorySchema = new Schema({
name: {type: String, required: true},
color: {type: String, required: true}
})
export default mongoose.model('Category', categorySchema, 'categories')
I found that on many projects using Next.js and Mongoose, including the example project by Next.js, they used the following syntax on the export to fix this problem:
export default mongoose.models.Category || mongoose.model('Category', categorySchema, 'categories')
This feels pretty weird and "bandaid solution"-esque, but it seems to do the trick at first glance; it prevents an overwrite if the model already exists. However, using TypeScript I started running into another problem, which after some time I found was being caused by that very line. Since the export was finnicky, TypeScript couldn't parse the Category model, and threw errors whenever I tried to use most of its properties or methods. I looked deeper into it and found some other people going around this by doing:
import mongoose from 'mongoose';
const { Schema } = mongoose;
const categorySchema = new Schema({
name: {type: String, required: true},
color: {type: String, required: true}
})
interface CategoryFields {
name: string,
color: string
}
type CategoryDocument = mongoose.Document & CategoryFields
export default (mongoose.models.Category as mongoose.Model<CategoryDocument>) || mongoose.model('Category', categorySchema, 'categories')
Again, this seems to do the trick but it's merely tricking TypeScript into believing there's nothing weird going on, when in reality there is.
Is there no real solution to fix the Model Overwrite problem without jumping through hoops and covering errors with other errors?
Thanks in advance!
Share Improve this question asked Jan 25, 2021 at 15:07 NicolasNicolas 894 silver badges9 bronze badges5 Answers
Reset to default 4 +100The key issue of this problem is that things inside mongoose.models
are all typed as Model<any>
by default.
So that type of
mongoose.models.Customer || mongoose.model("Customer", CustomerSchema)
will be inferred as Model<any>
since this is a more broaden type.
The goal is to type mongoose.models.Customer
correctly. And the type should be inferred instead of redefined.
Regarding your example, a solution can be like this:
const CustomerModel = mongoose.model('Customer', CustomerSchema)
// type `mongoose.models.Customer` same as `CustomerModel`
export const Customer = (mongoose.models.Customer as typeof CustomerModel) || CustomerModel;
This does not require adding extra interface
since it reused the model type you already defined.
export interface CategoryDoc extends Document {
name:string,
color:string
}
export interface CategoryModel extends Model<CategoryDoc> {}
then export it like this
// you might remove the 'categories'
export default mongoose.models.Category || mongoose.model<CategoryDoc,CategoryModel>('Category', categorySchema, 'categories')
I know this question is a bit old, but here's a TypeScript helper to solve it. Hope it helps someone in the future
export const Category = modelHelper('Category', categorySchema, 'categories')
// modelHelper.ts
import {
CompileModelOptions,
InferSchemaType,
Model,
model,
models,
Schema,
} from "mongoose"
export function modelHelper<TSchema extends Schema = any>(
name: string,
schema?: TSchema,
collection?: string,
options?: CompileModelOptions
) {
return (
(models[name] as Model<InferSchemaType<typeof schema>>) ||
model(name, schema, collection, options)
)
}
for typesefyty just do
export type UserDocument = InferSchemaType<typeof userSchema>;
export const User = models['user'] as Model<UserDocument> || model('user', userSchema);
Another approach you could use is casting the mongoose.models.Category as never in a function so it is ignored. You then keep full type inference from your schema without having to redefine an interface elsewhere.
Using your example:
const categorySchema = new mongoose.Schema({
name: { type: String, required: true },
color: { type: String, required: true },
});
function createModel() {
if (mongoose.models.Category) {
return mongoose.models.Category as never;
}
return mongoose.model("category", categorySchema);
}
const Category = createModel();
export default Category;
// accessing retrieved properties is then inferred properly
const category = await Category.findOne();
category?.name;
本文标签: javascriptHow to properly use Mongoose models in NextjsStack Overflow
版权声明:本文标题:javascript - How to properly use Mongoose models in Next.js? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741729324a2394768.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论