Knex.js多个链式查询

时间:2018-03-24 19:20:39

标签: node.js express promise es6-promise knex.js

我目前正在使用express进行项目,我正在使用knex.js来处理迁移和查询。

我仍在尝试掌握promises的概念以及如何使用knex运行多个查询。

我有以下代码将新记录插入我的数据库,该记录位于我的Unit model文件中。

this.addUnit = function(unit_prefixV, unit_nameV, unit_descriptionV, profile_id) {
         return new Promise(function(resolve, reject) {
             knex.insert({ unit_prefix: unit_prefixV, unit_name: unit_nameV, unit_description: unit_descriptionV })
                .into('units').then(function(unit) {
                    resolve(unit)
                }).catch(function(error) {
                    reject(error)
                })
         })
    }

在我的routes.js文件中,我会在邮件请求中调用此方法,如下所示:

app.post('/dashboard/unit/add', ensureAuthenticated, function(req, res) {
        let postErrors = []
        if (req.body.unit_name.trim() == "") {
            postErrors.push('Unit name cannot be empty.')
        }

        if (req.body.unit_prefix.trim() == "") {
            postErrors.push('Unit prefix cannot be empty.')
        }

        if (req.body.unit_description.trim() == "") {
            postErrors.push('Unit description cannot be empty.')
        }

        if (postErrors.length > 0) {
            res.render('addUnit', { errors: postErrors, user: req.user })
        } else {
            unitModel.addUnit(req.body.unit_prefix.trim(), req.body.unit_name.trim(), req.body.unit_description.trim(), req.session.passport.user.id).then(function(unit) {
                res.redirect('/dashboard')
            })
        }
    })

这成功地将新记录插入到我的units表中,但是,我想从users表中选择匹配profile_id的用户ID,然后在我的{{1}中插入另一条记录表。全部在users_units函数内。

作为参考,我的this.addUnit表包含:

  • ID
  • google_id

我的users表包含:

  • USER_ID
  • UNIT_ID

我尝试链接查询,但它只执行初始插入查询而不执行其他查询。这是一个相当丑陋的尝试:

users_units

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

你快到了。只需要掌握几个简单的要点:

  • 承诺只能解决一次
  • 无论如何都不需要明确的承诺,因为可以返回自然发生的承诺
  • return每个阶段的承诺......
  • ...直到最里面的阶段,返回的值是最终传递的结果。
  • 除非您想要注入自己的自定义错误消息或采取补救措施,否则无需显式处理错误。

把所有这些都带到了船上,你可以写下:

this.addUnit = function(unit_prefixV, unit_nameV, unit_descriptionV, profile_id) {
    return knex.insert({ 'unit_prefix':unit_prefixV, 'unit_name':unit_nameV, 'unit_description':unit_descriptionV }).into('units')
 // ^^^^^^
    .then(function(unit) {
        return knex('users').where({ 'google_id':profile_id }).select('id')
     // ^^^^^^
        .then(function(uid) {
            return knex.insert({ 'unit_id':unit, 'user_id':uid }).into('users_units')
         // ^^^^^^
            .then(function(user_units) {
                return { 'unit_id':unit, 'user_id':uid, 'user_units':user_units };
             // ^^^^^^
            });
        });
    });
}

如果调用者只对进程的成功/失败感兴趣而不是对完整的{ unit, uid, user_units }对象感兴趣,则可以省略最里面的.then()

this.addUnit = function(unit_prefixV, unit_nameV, unit_descriptionV, profile_id) {
    return knex.insert({ 'unit_prefix':unit_prefixV, 'unit_name':unit_nameV, 'unit_description':unit_descriptionV }).into('units')
    .then(function(unit) {
        return knex('users').where({ 'google_id':profile_id }).select('id')
        .then(function(uid) {
            return knex.insert({ 'unit_id':unit, 'user_id':uid }).into('users_units');
        });
    });
}

.addUnit()返回的承诺仍会传递user_units,来电者可以使用或忽略。{/ p>

这些解决方案(以及其他解决方案)有一​​个重要的附带条件;像这样的多阶段更新查询应该真正包含在transaction中 - 即允许回滚早期阶段的事情。否则,部分失败可能会使数据库处于某种不确定的状态。 This answer是一个好的起点。