Knex.js 多个链接查询
Knex.js multiple chained queries
我目前正在使用 express 开发一个项目,我正在使用 knex.js 来处理迁移和查询。
我仍在努力掌握承诺的概念以及如何使用 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
文件中,然后我根据 post 请求调用它,如下所示:
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
table,但是,我想 select 来自用户 table 的用户 ID 与匹配的 profile_id
然后再插入一条记录到我的users_units
table。全部在 this.addUnit
函数内。
作为参考,我的 users
table 包括:
- id
- google_id
我的 users_units
table 包括:
- user_id
- unit_id
我已经尝试链接查询,但它只执行初始插入查询而不执行其他查询。这是相当丑陋的尝试:
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) {
knex('users').where({ "google_id": profile_id }).select('id').then(function(uid) {
knex.insert({ user_id: uid, unit_id: unit }).into('users_units').then(function(user_units) {
resolve(user_unit)
}).catch(function(error) {
reject(error)
})
resolve(uid)
})
console.log(unit)
resolve(unit)
}).catch(function(error) {
reject(error)
})
})
}
任何帮助将不胜感激!
你快到了。有几个简单的要点可以掌握:
- 一个 Promise 只能被 reolved 一次
- 无论如何都不需要显式 Promise,因为可以返回自然发生的 Promise
return
每个阶段的 Promise ...
- ...一直到最里面,返回值就是最终传递的结果
- 除非您想注入自己的自定义错误消息或采取补救措施,否则无需明确处理错误。
考虑到所有这些,您可以这样写:
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 };
// ^^^^^^
});
});
});
}
如果调用者只对进程的success/failure感兴趣而不是完整的{ 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
,调用者可以使用或忽略它。
这些解决方案(以及其他解决方案)有一个主要的附带条件;像这样的 multi-stage 更新查询真的应该包含在 transaction - ie something that allows earlier stages to be rolled back. Otherwise a failure part way through is likely to leave the database in some indeterminate state. This answer 中,这是一个很好的起点。
我目前正在使用 express 开发一个项目,我正在使用 knex.js 来处理迁移和查询。
我仍在努力掌握承诺的概念以及如何使用 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
文件中,然后我根据 post 请求调用它,如下所示:
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
table,但是,我想 select 来自用户 table 的用户 ID 与匹配的 profile_id
然后再插入一条记录到我的users_units
table。全部在 this.addUnit
函数内。
作为参考,我的 users
table 包括:
- id
- google_id
我的 users_units
table 包括:
- user_id
- unit_id
我已经尝试链接查询,但它只执行初始插入查询而不执行其他查询。这是相当丑陋的尝试:
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) {
knex('users').where({ "google_id": profile_id }).select('id').then(function(uid) {
knex.insert({ user_id: uid, unit_id: unit }).into('users_units').then(function(user_units) {
resolve(user_unit)
}).catch(function(error) {
reject(error)
})
resolve(uid)
})
console.log(unit)
resolve(unit)
}).catch(function(error) {
reject(error)
})
})
}
任何帮助将不胜感激!
你快到了。有几个简单的要点可以掌握:
- 一个 Promise 只能被 reolved 一次
- 无论如何都不需要显式 Promise,因为可以返回自然发生的 Promise
return
每个阶段的 Promise ...- ...一直到最里面,返回值就是最终传递的结果
- 除非您想注入自己的自定义错误消息或采取补救措施,否则无需明确处理错误。
考虑到所有这些,您可以这样写:
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 };
// ^^^^^^
});
});
});
}
如果调用者只对进程的success/failure感兴趣而不是完整的{ 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
,调用者可以使用或忽略它。
这些解决方案(以及其他解决方案)有一个主要的附带条件;像这样的 multi-stage 更新查询真的应该包含在 transaction - ie something that allows earlier stages to be rolled back. Otherwise a failure part way through is likely to leave the database in some indeterminate state. This answer 中,这是一个很好的起点。