Проблема с Mongoose pre.save (), генерирующей определенные коды при создании записи - PullRequest
0 голосов
/ 15 апреля 2019

У меня есть коллекция Mongo со следующими свойствами:

{
    "_id" : ObjectId("384f1f06f72cc1b566e32f98"),
    "num" : 41,
    "product" : ObjectId("5c8921d8f9f7be241c0b02cf"),
    "data" : {
        "phone" : "123123123",
        "email" : "email@email.com",
        "name" : "John",
        "_id" : ObjectId("5ca34689ac024b579991fe26")
    },
    "generatedCode": "01-1FCS3";
}

В зависимости от типа продукта (как вы видите, это объект), я хочу генерировать новый код каждый раз, когда новый элементсоздал

    ProductSchema.pre('save', function(next) {

        if ((typeof this.generatedCode === 'undefined') || !this.generatedCode) {

            ProductSchema.find({_id: this.product}, function(error, existingProduct) {
                if (error) {
                    next(Error(error));
                }
                else {

                    if (existingProduct.length > 0) {

                        console.log("Type of product: "+ existingProduct[0].type);
                        generateCode(this,existingProduct[0].type).then(function(doc) {
                            console.log('Code generated:' + doc.generatedCode);
                            next();
                        }, function(err) {
                            console.error(err);
                            next(err);
                        });
                    }
                    else {
                        next(new Error("Error: Not found."));
                    }

                }
            });


    } else {
        next();
    }
});

    function generatedCode(doc,productType){
        var deferred = q.defer();
        try {
            console.log("Product type = "+ invoiceType);
            var ObjectId = require('mongoose').Types.ObjectId;    
            var generatedCode = '';

            switch(productType) {
                case 'TYPE1':
                    generatedCode = 'COD01-'+ random(5);
                break;
                case 'TYPE2':
                    generatedCode = 'COD02-'+ random(5);
                break;
                default: // other types
                    generatedCode = 'COD03-'+ random(5);
            }

            console.log("generatedCode = "+ generatedCode);
            var InvoiceModel = mongoose.model('Invoice', InvoiceSchema);

            // check that there are no records with that code

            InvoiceModel.find({generatedCode: generatedCode}, function(err, existingInvoice) {
                console.log('Find: '+ generatedCode);

                if(err) {
                    console.log(err);
                    deferred.reject(err);
                }

                if(existingInvoice.length > 0) {
                    console.log('Alredy exists ' + generatedCode + ' in db');
                    generatedCode(doc,productType).then(function(doc) {
                        deferred.resolve(doc);
                    }, function(err) {
                        deferred.reject(err);
                    });
                }
                else {
                    console.log("generatedCode = "+ generatedCode);
                    console.log("Doc = "+ doc);
                    doc.generatedCode = generatedCode;
                    deferred.resolve(doc);
                }
            });
        }
        catch(exception) {
            console.error(exception);
            deferred.reject(new Error(exception.message));
        }
        return deferred.promise;
    }

Я не знаю, почему возникла ошибка, но в строке "doc.generatedCode = generateCode;"возвращает null Кажется, что doc не существует, и я не понимаю, что не так ...

Я показываю вам отладку:

Type of product: GENERIC
Product type = GENERIC
generatedCode = COD03-8KORD
Find: COD03-8KORD
generatedCode = COD03-8KORD
Doc = null
[ERROR] (node.js:496) -> uncaughtException: Cannot set property 'code' of null

1 Ответ

1 голос
/ 15 апреля 2019

Значение this изменяется, когда вы находитесь внутри функции callback.То же самое происходит с вашим кодом здесь.Когда вы делаете ProductSchema.find и пытаетесь получить доступ к this внутри него, значение изменяется.Вам нужно сохранить ссылку на фактическое значение за пределами.

ProductSchema.pre('save', function(next) {

    if ((typeof this.generatedCode === 'undefined') || !this.generatedCode) {

        var that = this; // here create a reference to "this"

        ProductSchema.find({_id: this.product}, function(error, existingProduct) {

            ..
            ..

                // generateCode(this,existingProduct[0].type).then(function(doc) { // YOUR OLD CODE
                generateCode(that,existingProduct[0].type).then(function(doc) { // here, change "this" to "that" which is the actual reference of your object
            ..
            ..
...