Пн goose UnhandledPromiseRejectionWarning: MissingSchemaError: Схема не зарегистрирована для модели - PullRequest
0 голосов
/ 18 июня 2020

Я использую узел 14, пн goose 5.9.13. после того, как я добавил в свою модель метод stati c, я получаю следующую ошибку:

(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);

1 Ответ

0 голосов
/ 18 июня 2020

Модели должны быть импортированы перед маршрутами. Чтобы избежать ошибок 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');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...