Node JS通过一次“交易”将多个记录保存到Mongo

时间:2018-12-24 12:45:32

标签: node.js mongodb factory

请问您能为我提供解决我所面临问题的最佳方法的建议吗?我知道有很多方法可以给猫皮。我尝试了许多不同的方法,但似乎找不到解决方法。

总结:

我的节点js应用程序有一个get请求。当用户点击此GET URL时,我希望它获取该用户的记录,但是,如果没有该记录,我想根据预定义的列表为该用户创建一组记录。 (我需要一个 factory 之类的东西来创建批处理或记录,并在完成后给出结果。)

创建单个记录是可行的。但是我需要创建4。如果我尝试创建多个,则会得到...

UnhandledPromiseRejectionWarning:错误[ERR_HTTP_HEADERS_SENT]:无法将标头发送到客户端后设置标头,或者仅仅是一个普通错误,具体取决于我使用的版本。

基本上,一旦创建了多条记录,该记录的创建就会返回一个响应-我希望将其“合并”,并在完成后将组合结果发回。

我的模型很简单。看起来像这样:

/*____             _        _     __  __           _      _ 
 |  _ \           | |      | |   |  \/  |         | |    | |
 | |_) |_   _  ___| | _____| |_  | \  / | ___   __| | ___| |
 |  _ <| | | |/ __| |/ / _ \ __| | |\/| |/ _ \ / _` |/ _ \ |
 | |_) | |_| | (__|   <  __/ |_  | |  | | (_) | (_| |  __/ |
 |____/ \__,_|\___|_|\_\___|\__| |_|  |_|\___/ \__,_|\___|_|
*/
const mongoose = require('mongoose');
const dbSchema = mongoose.Schema;

const bucketSchema = new dbSchema({
    name: {
        type: String,
        required: true,
        unique: false
    },
    createdby: {
        type: dbSchema.Types.ObjectId,
        ref: 'user'
    },
    createdon: {
        type: Date,
        default: Date.now
    },
    isforarchive: {
        type: Boolean,
        required: true,
        default: false
    },
    cards: [
        {
            card: {
                type: dbSchema.Types.ObjectId,
                ref: 'card'
            }
        }
    ]
});

module.exports = bucket = mongoose.model('bucket', bucketSchema);

当我创建单个记录时,此代码有效。但是,我需要为用户创建4个存储桶:-ToDo,Busy,Done和Archive。

下面的代码只能创建一个单独的桶-ToDo。

const ToDo = new Bucket({
    name: 'To-Do',
    createdby: null,
    createdon: Date.now(),
    isforarchive: false,
    cards: [ {} ]
});

// @route get:/api/tms/buckets
// @desc Gets user buckets or creates a set of buckets for the user if they do not exist.
// @access Private
router.get(
    '/',
    passport.authenticate('jwt', {
        session: false
    }),
    (req, res) => {
        console.log('About to search buckets...');
        Bucket.find({ createdby: req.user.id })
            .then((found) => {
                console.log('Checking if found');
                console.log(`Length ${found.length}`); // Zero when none found
                if (found.length > 0) {
                    res.json(found);
                } else {
                    console.log('Creating ToDo');
                    ToDo.createdby = req.user.id;
                    ToDo.save().then((saved) => res.json(saved));
                }
            })
            .catch((err) => {
                const errors = {};
                errors.getbuckets = 'Encountered a problem getting buckets.';
                errors.error = err;
                res.status(400).json(errors);
            });
    }
);

为了尝试帮助我,我创建了一个帮助器类./buckethelper.js来帮助我。我已经尝试了promises等,但是无法解决发送导致上述错误的响应的第一条记录的创建问题。

我在辅助程序类中尝试了许多其他选项,但这些选项我无法上班。这是我尝试解决的许多问题,其中之一是我希望代码同步且串行而不是并行运行。

这是我的助手班。

const Bucket = require('./model');
/*
//PLEASE NOTE THAT THIS SECTION IS COMMENTED OUT.
function CreateBucket(Name, CreatedBy, CreatedOn, IsForArchive, Cards) {
    this.name = Name;
    this.createdby = CreatedBy;
    this.createdon = CreatedOn;
    this.isforarchive = IsForArchive;
    this.cards = Cards;
}

const Buckets = [];
Buckets.push(new CreateBucket('To-Do', '', Date.now(), false, [ {} ]));
Buckets.push(new CreateBucket('Busy', '', Date.now(), false, [ {} ]));
Buckets.push(new CreateBucket('Done', '', Date.now(), false, [ {} ]));
Buckets.push(new CreateBucket('Archive', '', Date.now(), true, [ {} ]));
*/
const ToDo = new Bucket({
    name: 'To-Do',
    createdby: null,
    createdon: Date.now(),
    isforarchive: false,
    cards: [ {} ]
});
const Busy = new Bucket({
    name: 'Busy',
    createdby: null,
    createdon: Date.now(),
    isforarchive: false,
    cards: [ {} ]
});
const Done = new Bucket({
    name: 'Done',
    createdby: null,
    createdon: Date.now(),
    isforarchive: false,
    cards: [ {} ]
});
const Archive = new Bucket({
    name: 'Archive',
    createdby: null,
    createdon: Date.now(),
    isforarchive: true,
    cards: [ {} ]
});



var result = [];

function fnSaveToDo(UserId) {
    console.log(`Saving To Do ...`);
    ToDo.createdby = UserId;
    result.push(Bucket.save(ToDo));
}

function fnSaveBusy(UserId) {
    Busy.createdby = UserId;
    result.push(Bucket.insert(Busy));
}

function fnSaveDone(UserId) {
    Done.createdby = UserId;
    result.push(Bucket.insert(Done));
}

function fnSaveArchive(UserId) {
    Archive.createdby = UserId;
    result.push(Bucket.insert(Archive));
    return result;//I want to return the combined results
}

//Synchronous call stack that execute in series not parallel
function CreateBuckets(UserId, fnSaveToDo, fnSaveBusy, fnSaveDone, fnSaveArchive) {
    console.log('Started the saving process ...');
    fnSaveToDo(UserId);
    fnSaveBusy(UserId);
    fnSaveDone(UserId);
    fnSaveArchive(UserId);
 }
 CreateBuckets(
    function() {
        console.log('User id callback?');
    },
    function() {
        console.log('ToDo saved ...');
    },
    function() {
        console.log('Busy saved ...');
    },
    function() {
        console.log('Done saved ...');
    },
    function() {
        console.log('Archive saved ...');
    }
 );

 module.exports = CreateBuckets;

调用我的助手的代码看起来像这样,它是上面代码的一部分;

Bucket.find({ createdby: req.user.id })
            .then((found) => {
                console.log('Checking if found');
                console.log(`Length ${found.length}`); // Zero when none found
                if (found.length > 0) {
                    res.json(found);
                } else {
                    //console.log('Creating ToDo');
                    res.json(CreateBuckets(req.user.id,fnSaveToDo,fnSaveBusy, fnSaveDone, fnSaveArchive));
                    // ToDo.createdby = req.user.id;
                    // ToDo.save().then((saved) => res.json(saved));    
                }
            })
            .catch((err) => {
                const errors = {};
                errors.getbuckets = 'Encountered a problem getting buckets.';
                errors.error = err;
                res.status(400).json(errors);
            });

我希望我对问题的描述清楚。

如果或当我找到解决方案时,我会发布它。在这里呆了几天,没有任何成功。

亲切的问候 克雷格

2 个答案:

答案 0 :(得分:0)

您可以在此处使用 here 方法进行批量插入,并在操作中利用async / await,因为该方法返回了promise。

例如,您的路线可以重写为

router.get('/', passport.authenticate('jwt', {session: false }), async (req, res) => {
    try {
        console.log('About to search buckets...');
        const found = await Bucket.find({ createdby: req.user.id })

        console.log('Checking if found');
        console.log(`Length ${found.length}`); // Zero when none found
        if (found.length > 0) {
            res.json(found);
        } else {
            console.log('Creating ToDos');
            const todos = ['To-Do', 'Busy', 'Done', 'Archive'].map(name => (
                {
                    name,
                    createdby: req.user.id,
                    createdon: Date.now(),
                    isforarchive: (name == 'Archive'),
                    cards: [ {} ]
                }
            ));
            const saved = await ToDo.insertMany(todos);
            res.json(saved);
        }
    } catch (err) {
        const errors = {};
        errors.getbuckets = 'Encountered a problem getting buckets.';
        errors.error = err;
        res.status(400).json(errors);
    }
});

答案 1 :(得分:0)

谢谢您的解决方案。但是,我无法等待上班。这是我的解决方案。我将对其进行重构,但是它可以工作。

const DefaultBuckets = [ 'To Do', 'Busy', 'Done', 'Archive' ];

// @route get:/api/tms/buckets
// @desc Gets user buckets or creates a set of buckets for the user if they do not exist.
// @access Private
router.get(
    '/',
    passport.authenticate('jwt', {
        session: false
    }),
    (req, res) => {
        console.log('About to search buckets...');
        Bucket.find({ createdby: req.user.id })
            .then((found) => {
                console.log('Checking if found');
                console.log(`Length ${found.length}`); // Zero when none found
                if (found.length > 0) {
                    console.log('returning what is in db');
                    res.json(found);
                } else {
                    // console.log('Creating buckets ...');
                    const defaults = DefaultBuckets.map((name) => ({
                        name,
                        createdby: req.user.id,
                        createdon: Date.now(),
                        isforarchive: name == 'Archive',
                        cards: [ {} ]
                    }));
                    Bucket.insertMany(defaults, (err, docs) => {
                        let errors = {};
                        // Docs are the saved records from the db
                        if (docs) {
                            res.json(docs);
                        }else{
                            errors.message = 'Could not create buckets';
                            errors.InsertMany = err;
                            res.status(400).json(errors);
                        }                   
                    });
                }
            })
            .catch((err) => {
                const errors = {};
                errors.getbuckets = 'Encountered a problem getting buckets.';
                errors.error = err;
                res.status(400).json(errors);
            });
    }
);