使用knex
我想向现有表中添加2个其他列。为了预先存在记录,我想基于计算添加一个值。以下是我的迁移文件。它在第二行上失败:Cannot read property 'resolve' of undefined
。
exports.up = function (knex, Promise) {
return Promise.resolve()
.then(function(){
... cut to shorten question...
})
};
更新:我删除了Promise
,现在下面有迁移代码。这仍然会产生两个错误,可能与forEach
循环有关,并且它不会等待循环的一部分完成才继续进行下一部分(但是我不知道该怎么做)循环):
未处理的拒绝Migration Migrationed:迁移表已被锁定
交易查询已经完成,请使用DEBUG = knex:tx来获取更多信息
const Coupon = require('../../models/coupon');
const Plan = require('../../models/plan');
exports.up = function (knex) {
return knex.schema.table('transactions', (table) => {
table.decimal('plan_price', 10, 2);
table.decimal('discount', 10, 2).defaultTo(0);
})
.then(function(return_value){
knex.select().from('transactions')
.then((transactions) => {
transactions.forEach(async function(trans){
let original_price;
let total_coupon_discount = 0;
const plan = await Plan.where({id: trans.plan_id}).fetch();
if (plan) { original_price = plan.get("price") };
if (trans.coupon_id) {
const coupon = await Coupon.where({id: trans.coupon_id}).fetch();
if (coupon) {
total_coupon_discount = coupon.get("discount_amount");
original_price = trans.amount_ex_vat + couponAmount;
}
}
const promise = await knex('transactions')
.where('id', '=', trans.id)
.update({
plan_price: original_price,
discount: total_coupon_discount
}).catch(function(error){
console.log(error)
}).then(function(){
console.log('Added data to transaction record');
})
})
})
return return_value;
})
};
exports.down = function (knex) {
return knex.schema.table('transactions', (table) => {
table.dropColumn('plan_price');
table.dropColumn('discount');
});
};
Update2 :@ Rich Churcher的答案中建议的迁移语法使迁移工作得以实现。但是有关MigrationLock的错误消息仍然存在。 Here讨论了类似的问题。建议从migration_table
删除锁,但是即使完全清空该表也对我没有影响。
因此我在DEBUG=knex:*
中添加了variables.env
,因为该站点也建议这样做。然后,当我运行迁移时,我得到以下输出。您知道什么可能导致错误以及如何解决吗?
Using environment: development
knex:client acquired connection from pool: __knexUid1 +0ms
knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +0ms
knex:bindings [ 'migrations' ] undefined +0ms
knex:client releasing connection to pool: __knexUid1 +40ms
knex:client acquired connection from pool: __knexUid1 +2ms
knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +40ms
knex:bindings [ 'migrations_lock' ] undefined +39ms
knex:client releasing connection to pool: __knexUid1 +5ms
knex:client acquired connection from pool: __knexUid1 +2ms
knex:query select * from `migrations_lock` undefined +9ms
knex:bindings [] undefined +10ms
knex:client releasing connection to pool: __knexUid1 +22ms
knex:client acquired connection from pool: __knexUid1 +22ms
knex:query select `name` from `migrations` order by `id` asc undefined +60ms
knex:bindings [] undefined +62ms
knex:client releasing connection to pool: __knexUid1 +25ms
knex:tx trx2: Starting top level transaction +0ms
knex:client acquired connection from pool: __knexUid1 +329ms
knex:query BEGIN; trx2 +348ms
knex:bindings undefined trx2 +347ms
knex:query update `migrations_lock` set `is_locked` = ? where `is_locked` = ? trx2 +18ms
knex:bindings [ 1, 0 ] trx2 +25ms
knex:client acquired connection from pool: __knexUid3 +47ms
knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +17ms
knex:bindings [ 'migrations' ] undefined +8ms
knex:query select * from information_schema.tables where table_name = ? and table_schema = database() trx2 +6ms
knex:bindings [ 'migrations' ] trx2 +6ms
knex:client releasing connection to pool: __knexUid3 +13ms
knex:client acquired connection from pool: __knexUid3 +18ms
knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +26ms
knex:bindings [ 'migrations_lock' ] undefined +26ms
knex:query select * from information_schema.tables where table_name = ? and table_schema = database() trx2 +2ms
knex:bindings [ 'migrations_lock' ] trx2 +3ms
knex:client releasing connection to pool: __knexUid3 +6ms
knex:client acquired connection from pool: __knexUid3 +1ms
knex:query select * from `migrations_lock` undefined +4ms
knex:bindings [] undefined +3ms
knex:query select * from `migrations_lock` trx2 +2ms
knex:bindings [] trx2 +18ms
knex:client releasing connection to pool: __knexUid3 +22ms
knex:client acquired connection from pool: __knexUid3 +23ms
knex:query select `name` from `migrations` order by `id` asc undefined +66ms
knex:bindings [] undefined +51ms
knex:query select `name` from `migrations` order by `id` asc trx2 +7ms
knex:bindings [] trx2 +26ms
knex:client releasing connection to pool: __knexUid3 +55ms
knex:tx trx4: Starting top level transaction +193ms
knex:client acquired connection from pool: __knexUid3 +3ms
knex:query BEGIN; trx4 +27ms
knex:bindings undefined trx4 +8ms
knex:query select max(`batch`) as `max_batch` from `migrations` trx2 +23ms
knex:bindings [] trx2 +43ms
knex:query update `migrations_lock` set `is_locked` = ? where `is_locked` = ? trx4 +25ms
knex:bindings [ 1, 0 ] trx4 +5ms
knex:query alter table `transactions` add `plan_price` decimal(10, 2), add `discount` decimal(10, 2) default '0' trx2 +13ms
knex:bindings [] trx2 +20ms
Can't take lock to run migrations: Migration table is already locked
If you are sure migrations are not running you can release the lock manually by deleting all the rows = require(migrations lock table: migrations_lock
knex:query ROLLBACK trx4 +71ms
knex:bindings undefined trx4 +64ms
knex:tx trx4: releasing connection +136ms
knex:client releasing connection to pool: __knexUid3 +180ms
Unhandled rejection MigrationLocked: Migration table is already locked
(No stack trace)
From previous event:
at Migrator._getLock (C:\Users\Xxx\node_modules\knex\lib\migrate\Migrator.js:328:13)
at Migrator._runBatch (C:\Users\Xxx\node_modules\knex\lib\migrate\Migrator.js:343:12)
at knex.transaction (C:\Users\Xxx\node_modules\knex\lib\migrate\Migrator.js:92:25)
at init.then.then (C:\Users\Xxx\node_modules\knex\lib\transaction.js:91:24)
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
From previous event:
at Transaction._promise.Bluebird.using (C:\Users\Xxx\node_modules\knex\lib\transaction.js:77:12)
at runCallback (timers.js:705:18)
From previous event:
at new Transaction (C:\Users\Xxx\node_modules\knex\lib\transaction.js:57:30)
at new Transaction_MySQL (C:\Users\Xxx\node_modules\knex\lib\dialects\mysql\transaction.js:7:1)
at Client_MySQL.transaction (C:\Users\Xxx\node_modules\knex\lib\dialects\mysql\index.js:52:12)
at Function.transaction (C:\Users\Xxx\node_modules\knex\lib\util\make-knex.js:40:31)
at migrationListResolver.listAllAndCompleted.then.then (C:\Users\Xxx\node_modules\knex\lib\migrate\Migrator.js:91:28)
From previous event:
at Migrator.latest (C:\Users\Xxx\node_modules\knex\lib\migrate\Migrator.js:72:8)
at Command.commander.command.description.option.action (C:\Users\Xxx\node_modules\knex\bin\cli.js:185:18)
at Command.listener (C:\Users\Xxx\node_modules\knex\node_modules\commander\index.js:360:8)
at Command.emit (events.js:189:13)
at Command.parseArgs (C:\Users\Xxx\node_modules\knex\node_modules\commander\index.js:799:12)
at Command.parse (C:\Users\Xxx\node_modules\knex\node_modules\commander\index.js:563:21)
at Liftoff.invoke (C:\Users\Xxx\node_modules\knex\bin\cli.js:344:13)
at Liftoff.execute (C:\Users\Xxx\node_modules\liftoff\index.js:201:12)
at module.exports (C:\Users\Xxx\node_modules\flagged-respawn\index.js:51:3)
at Liftoff.<anonymous> (C:\Users\Xxx\node_modules\liftoff\index.js:191:5)
at C:\Users\Xxx\node_modules\liftoff\index.js:149:9
at C:\Users\Xxx\node_modules\v8flags\index.js:138:14
at C:\Users\Xxx\node_modules\v8flags\index.js:41:14
at C:\Users\Xxx\node_modules\v8flags\index.js:53:7
at process._tickCallback (internal/process/next_tick.js:61:11)
knex:query select * from `transactions` trx2 +185ms
knex:bindings [] trx2 +227ms
knex:client acquired connection from pool: __knexUid3 +201ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +88ms
knex:bindings [ 7, 1 ] trx4 +73ms
knex:client releasing connection to pool: __knexUid3 +158ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +137ms
knex:bindings [ 1725, 0, 1 ] trx2 +109ms
• Added original price and discount to transaction: 1
knex:client acquired connection from pool: __knexUid3 +35ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +33ms
knex:bindings [ 2, 1 ] trx4 +33ms
knex:client releasing connection to pool: __knexUid3 +2ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +3ms
knex:bindings [ 195, 0, 2 ] trx2 +4ms
• Added original price and discount to transaction: 2
knex:client acquired connection from pool: __knexUid3 +51ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +50ms
knex:bindings [ 6, 1 ] trx4 +49ms
knex:client releasing connection to pool: __knexUid3 +3ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +4ms
knex:bindings [ 975, 0, 3 ] trx2 +4ms
• Added original price and discount to transaction: 3
knex:client acquired connection from pool: __knexUid3 +36ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +35ms
knex:bindings [ 5, 1 ] trx4 +35ms
knex:client releasing connection to pool: __knexUid3 +10ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +31ms
knex:bindings [ 650, 0, 4 ] trx2 +31ms
• Added original price and discount to transaction: 4
knex:client acquired connection from pool: __knexUid3 +56ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +34ms
knex:bindings [ 5, 1 ] trx4 +34ms
knex:client releasing connection to pool: __knexUid3 +2ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +9ms
knex:bindings [ 650, 0, 5 ] trx2 +31ms
• Added original price and discount to transaction: 5
knex:client acquired connection from pool: __knexUid3 +62ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +55ms
knex:bindings [ 6, 1 ] trx4 +34ms
knex:client releasing connection to pool: __knexUid3 +4ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +6ms
knex:bindings [ 975, 0, 6 ] trx2 +29ms
• Added original price and discount to transaction: 6
knex:client acquired connection from pool: __knexUid3 +64ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +63ms
knex:bindings [ 6, 1 ] trx4 +39ms
knex:client releasing connection to pool: __knexUid3 +2ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +4ms
knex:bindings [ 975, 0, 7 ] trx2 +34ms
• Added original price and discount to transaction: 7
knex:client acquired connection from pool: __knexUid3 +66ms
knex:query select `plans`.* from `plans` where `id` = ? limit ? trx4 +64ms
knex:bindings [ 5, 1 ] trx4 +34ms
knex:client releasing connection to pool: __knexUid3 +3ms
knex:query update `transactions` set `plan_price` = ?, `discount` = ? where `id` = ? trx2 +29ms
knex:bindings [ 650, 0, 8 ] trx2 +30ms
• Added original price and discount to transaction: 8
knex:query insert into `migrations` (`batch`, `migration_time`, `name`) values (?, ?, ?) trx2 +36ms
knex:bindings [ 4,
knex:bindings 2020-01-09T21:13:03.923Z,
knex:bindings '20200105152452_add_plan_price_and_discount_to_transactions.js' ] trx2 +35ms
knex:query update `migrations_lock` set `is_locked` = ? trx2 +24ms
knex:bindings [ 0 ] trx2 +37ms
knex:query COMMIT; trx2 +42ms
knex:bindings undefined trx2 +44ms
knex:tx trx2: releasing connection +945ms
knex:client releasing connection to pool: __knexUid1 +146ms
Batch 4 run: 1 migrations
knex -V
返回:“ Knex CLI版本:0.20.2”和“ Knex本地版本:0.20.3”。
完整的迁移文件如下所示:
const Coupon = require('../../models/coupon');
const Plan = require('../../models/plan');
exports.up = knex =>
knex.schema
.table('transactions', table => {
table.decimal('plan_price', 10, 2);
table.decimal('discount', 10, 2).defaultTo(0);
})
.then(() => {
return knex('transactions').then(async transactions => {
for (let trans of transactions) {
let original_price;
let total_coupon_discount = 0;
const plan = await Plan.where({id: trans.plan_id}).fetch();
if (plan) {
original_price = plan.get("price");
} else {
original_price = null;
}
if (trans.coupon_id) {
const coupon = await Coupon.where({id: trans.coupon_id}).fetch();
if (coupon) {
const amount_ex_vat = trans.amount_ex_vat;
const couponAmount = coupon.get("discount_amount");
let couponPercentage = 1;
if ( coupon.get("discount_percentage") > 0 ) {
couponPercentage = 1.0 / ( (100.0 - coupon.get("discount_percentage")) / 100.0 );
}
original_price = (amount_ex_vat * couponPercentage) + couponAmount;
total_coupon_discount = original_price - amount_ex_vat;
}
}
await knex("transactions")
.where('id', '=', trans.id)
.update({
plan_price: original_price,
discount: total_coupon_discount
}).catch(function(error){
console.log(error)
}).then(function(){
console.log(' • Added original price and discount to transaction: ' + trans.id);
})
}
});
});
exports.down = function (knex) {
return knex.schema.table('transactions', (table) => {
table.dropColumn('plan_price');
table.dropColumn('discount');
});
};
答案 0 :(得分:2)
Knex不再使用第二个Promise
参数,因为它又转而使用了原生的Promise。因此,Promise
在迁移过程中是undefined
,因此绝对没有.resolve
属性。
有人认为返回Promise.resolve().then
是个好主意,这确实很奇怪。您要执行的是模式修改,然后是数据修改。看起来像这样:
return knex.schema.table("transactions", t => {
t.decimal('plan_price', 10, 2);
// etc
})
.then(() =>
knex("transactions")
.then(
// Update values here
);
)
.catch(console.error)
此外,您发现for_each
并不总是非常适合异步
工作。但是,我们仍然可以通过编写更复杂的查询(加入
其他表格以获取我们想要的值)或通过修改当前表格以更好地与
承诺:
exports.up = knex =>
knex.schema
.table("transactions", t => {
t.decimal("plan_price", 10, 2);
t.decimal("discount", 10, 2).defaultTo(0);
})
.then(() => {
return knex("transactions").then(async transactions => {
for (let trans of transactions) {
let original_price;
let total_coupon_discount = 0;
const plan = await Plan.where({ id: trans.plan_id }).fetch();
if (plan) {
original_price = plan.get("price");
}
if (trans.coupon_id) {
const coupon = await Coupon.where({ id: trans.coupon_id }).fetch();
if (coupon) {
total_coupon_discount = coupon.get("discount_amount");
original_price = trans.amount_ex_vat + couponAmount;
}
}
await knex("transactions")
.where("id", "=", trans.id)
.update({
plan_price: original_price,
discount: total_coupon_discount
});
}
});
});
我显然无法说出其他代码的正确性(在我看来像书架?),因为
我没有您的架构,但这是总体思路。基本上,当你想使用
async
/ await
与for... of
搭配使用,可保持一切顺畅顺畅。
我认为值得注意的是,这种方法在一张大桌子上可能会比较慢,只有三个
transactions
的每行单独的阻止查询。