猫鼬未处理承诺拒绝警告:缺少架构错误:尚未为模型注册架构



我正在使用节点 14,猫鼬 5.9.13。 在我向模型添加静态方法后,出现以下错误:

(node:973) UnhandledPromiseRejectionWarning: MissingSchemaError: Schema hasn't been registered for model "Publisher".
Use mongoose.model(name, schema)

方法如下:

productSchema.statics.fullPopulate = function(isAdmin) {
let p = 'details.publisher details.serie details.genres details.authors details.translators details.lecturers details.courses details.grades details.majors details.exams';
if (isAdmin) {
p += ' sources.reference';
}
return p;
};

如您所见,它返回填充产品模型所需的所有关系的列表。 当我在产品模型的开头添加以下行时,错误消失了。

const Publisher = require('./publisher.model');
const Person = require('./person.model');
const Major = require('./major.model');
const Grade = require('./grade.model');
const Exam = require('./exam.model');
const Goal = require('./goal.model');
const Serie = require('./serie.model');
const Course = require('./course.model');
const Genre = require('./genre.model');

但正如您可能猜到的那样,我收到 eslint 错误,因为有些变量根本没有使用。 错误到底是什么? 我其实不明白。

这是我完整的产品模型文件。

'use strict';
const mongoose = require('mongoose');
const path = require('path');
const Schema = mongoose.Schema;
const sequencePlugin = require('../utils/sequence-plugin.util');
const imagePlugin = require('../utils/image-plugin.util');
const ProductStatuses = require('../enums/product-status.enum');
const Categories = require('../enums/category.enum');
const Scopes = require('../enums/scope.enum');
const BookSizes = require('../enums/book-size.enum');
const BookCovers = require('../enums/book-cover.enum');
const envConfig = require('../configs/env.config')();
const Errors = require('../enums/error.enum');
const LogicError = require('../utils/logic-error.util');

mongoose.set('useCreateIndex', true);
const pdfSchema = new Schema({
_id: false,
referenceUrl: String,
name: String,
}, {
toObject: {virtuals: true},
toJSON: {virtuals: true}
});
pdfSchema.virtual('url').get(function () {
if (!this.name) {
return undefined;
}
return `${envConfig.CDN_URL}/products/${this.$parent.code}/pdfs/${this.name}`;
});
const productSchema = new Schema({
ketabchiStatus: {type: String, enum: Object.values(ProductStatuses), index: true},
status: {type: String, enum: Object.values(ProductStatuses), index: true},
category: {type: String, enum: Object.values(Categories), index: true},
scope: {type: String, enum: Object.values(Scopes), required: true, index: true},
title: {type: String, required: true},
name: {type: String, required: true},
subtitle: String,
slug: {type: String, required: true},
stock: {
liquid: {type: Number, default: 0, index: true},
solid: {type: Number, default: 0, index: true},
},
barcode: {type: String, index: true, unique: true, sparse: true},
discount: Number,
aggregateReview: { rating: Number, count: {type: Number, default: 0}},
counts: {
views: {type: Number, default: 0, index: true},
favorites: {type: Number, default: 0, index: true},
sales: {type: Number, default: 0, index: true},
notices: {type: Number, default: 0, index: true},
comments: {type: Number, default: 0, index: true},
replies: {type: Number, default: 0, index: true},
},
weight: {
type: Number,
validate : {
validator : Number.isInteger,
message   : '{VALUE} is not an integer value'
}
},
metaTitle: {type: String, required: true},
metaDescription: {type: String, required: true},
details: {
publisher: {type: Schema.ObjectId, ref: 'Publisher', index: true},
authors: {type: [{type: Schema.ObjectId, ref: 'Person'}], index: true},
translators: {type: [{type: Schema.ObjectId, ref: 'Person'}], index: true},
editors: {type: [{type: Schema.ObjectId, ref: 'Person'}], index: true},
illustrators: {type: [{type: Schema.ObjectId, ref: 'Person'}], index: true},
lecturers: {type: [{type: Schema.ObjectId, ref: 'Person'}], index: true},
grades: {type: [{type: Schema.ObjectId, ref: 'Grade'}], index: true},
majors: {type: [{type: Schema.ObjectId, ref: 'Major'}], index: true},
courses: {type: [{type: Schema.ObjectId, ref: 'Course'}], index: true},
genres: {type: [{type: Schema.ObjectId, ref: 'Genre'}], index: true},
goals: {type: [{type: Schema.ObjectId, ref: 'Goal'}], index: true},
serie: {type: Schema.ObjectId, ref: 'Serie', index: true},
exams: {type: [{type: Schema.ObjectId, ref: 'Exam'}], index: true},
year: Number,
pages: Number,
pieces: Number,
size: {type: String, enum: Object.values(BookSizes)},
cover: {type: String, enum: Object.values(BookCovers)},
richDescription: String,
description: String,
pdf: {type: pdfSchema, default: {}}
},
sources: [{
_id: false,
reference: {type: Schema.ObjectId, ref: 'Reference', required: true},
url: {type: String, required: true, unique: true, sparse: true},
status: {type: String, enum: Object.values(ProductStatuses)},
use: {type: Boolean, default: true},
price: Number,
sku: String
}],
tags: [{type: String}],
_tags: [{type: String}],
links: {
melli: String,
goodreads: String,
ketabir: String
},
}, {
toObject: {virtuals: true},
toJSON: {virtuals: true},
timestamps: {createdAt: 'createdAt', updatedAt: 'updatedAt'},
});
productSchema.virtual('webUrlRel').get(function () {
return `/product/${this.code}/${encodeURIComponent(this.slug)}`;
});
productSchema.virtual('webUrl').get(function () {
return `${envConfig.WEBSITE_URL}${this.webUrlRel}`;
});
productSchema.virtual('stockCount').get(function () {
if (!this.stock) {
return 0;
}
return this.stock.solid - this.stock.liquid;
});
productSchema.virtual('originalPrice').get(function () {
if (!this.sources) {
return undefined;
}
for (let source of this.sources) {
if (source.status === ProductStatuses.AVAILABLE) {
return source.price;
}
}
for (let source of this.sources) {
if (source.price) {
return source.price;
}
}
return undefined;
});
productSchema.virtual('beforeDiscountPrice').get(function () {
if (!this.discount) {
return undefined;
}
return this.get('originalPrice');
});
productSchema.virtual('price').get(function () {
if (!this.discount) {
return this.get('originalPrice');
}
return Math.round(this.get('originalPrice')*(1 - this.discount/100));
});
// Backward compatibility
productSchema.virtual('images').get(function () {
return [this.image];
});
productSchema.index({
name: 'text',
_tags: 'text',
status: 'text',
title: 'text',
}, {
weights: {
name: 10,
_tags: 10,
status: 6,
title: 2
}
});
productSchema.statics.validate = function (productData) {
if (!productData) {
throw new LogicError(Errors.MISSING_FIELD, {field: 'product'});
}
if (!productData.name && !productData.title) {
throw new LogicError(Errors.MISSING_FIELD, {field: 'name|title'});
}
if (productData.status === ProductStatuses.AVAILABLE && !productData.price) {
throw new LogicError(Errors.MISSING_FIELD, {field: 'price'});
}
if (productData.barcode && productData.barcode.length !== 13) {
throw new LogicError(Errors.INVALID_VALUE, {field: 'barcode'});
}
if (productData.details.metaDescription &&
productData.details.metaDescription !== productData.details.metaDescription.trim()) {
throw new LogicError(Errors.INVALID_VALUE, {field: 'metaDescription'});
}
if (productData.details.richDescription &&
productData.details.richDescription !== productData.details.richDescription.trim()) {
throw new LogicError(Errors.INVALID_VALUE, {field: 'richDescription'});
}
// if (productData.category === Categories.BOOK) { TODO: publisher is required
//    if (!productData.details.publisher) {
//        throw new LogicError(Errors.MISSING_FIELD, { field: 'publisher' });
//    }
// }
};
productSchema.statics.exportData = function (products) {
let data = [];
for (let p of products) {
p.sources = p.sources.filter(
p => p.status === ProductStatuses.AVAILABLE
);
let refName = '', qoqSKU = '', gbSKU = '', cbSKU;
if (p.scope === Scopes.SCHOOL) {
refName = 'کمک درسی';
} else if (p.sources.length > 0) {
p.sources = p.sources.sort((a, b) => {
return parseInt(a.reference.priority) - parseInt(b.reference.priority);
});
refName = p.sources.map(el => el.reference.name).join(', ');
let gostaresh = p.sources.find(s => s.reference.code === '106'),
qoqnoos = p.sources.find(s => s.reference.code === '101'),
cbook = p.sources.find(s => s.reference.code === '104');
qoqSKU = qoqnoos ? qoqnoos.sku : '';
gbSKU = gostaresh ? gostaresh.sku : '';
cbSKU = cbook ? cbook.sku : '';
}
data.push([
p.code,
p.originalPrice/1000,
p.title,
p.details.publisher.name,
p.stockCount,
refName,
qoqSKU,
gbSKU,
cbSKU,
]);
}
return data;
};
const depotThreshold = 10;
productSchema.methods.determineStatus = function()  {
if (this.ketabchiStatus !== ProductStatuses.AVAILABLE) {
return this.ketabchiStatus;
}
if (this.stockCount > depotThreshold) {
return ProductStatuses.AVAILABLE;
}
if (this.sources.length === 0) {
return ProductStatuses.UNAVAILABLE;
}
let source = this.sources.find(s => s.use && s.status === ProductStatuses.AVAILABLE);
if (source) {
return ProductStatuses.AVAILABLE;
}
source = this.sources.find(s => s.use && s.status === ProductStatuses.SOON);
if (source) {
return ProductStatuses.SOON;
}
return ProductStatuses.UNAVAILABLE;
};
productSchema.statics.hiddenSelect = function()  {
return '-counts -sources.reference -sources.url -sources.sku -stock -sales';
};
productSchema.statics.compactSelect = function() {
return {_id: 0, code: 1, slug: 1, title: 1, image: 1, subtitle: 1, discount: 1,
status: 1, 'aggregateReview.rating': 1, 'sources.status': 1,
'sources.price': 1};
};
productSchema.statics.path = function()  {
return path.join(envConfig.CONTENTS_DIR, 'products');
};
productSchema.statics.thumbSize = function()  {
return {width: 130, height: 185};
};
productSchema.statics.fullPopulate = function(isAdmin) {
let p = 'details.publisher details.serie details.genres details.authors details.translators details.lecturers details.courses details.grades details.majors details.exams';
if (isAdmin) {
p += ' sources.reference';
}
return p;
};


productSchema.plugin(sequencePlugin, {entityName: 'product'});
productSchema.plugin(imagePlugin, {entityName: 'product'});
module.exports = mongoose.model('Product', productSchema);

模型必须在路由之前导入。为避免 eslint 错误,您可以在产品模型开始时导入它们,而无需将它们分配给任何变量,如下所示。

require('./publisher.model');
require('./person.model');
require('./major.model');
require('./grade.model');
require('./exam.model');
require('./goal.model');
require('./serie.model');
require('./course.model');
require('./genre.model');

最新更新