猫鼬pre.save()在记录创建时生成特定代码的问题

时间:2019-04-15 13:37:04

标签: node.js mongoose mongoose-schema

我有一个具有以下属性的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.genicCode = 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 个答案:

答案 0 :(得分:1)

当您在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
            ..
            ..