提交事务后如何return查询数据(使用knex.js)?

How to I return query data after committing a transaction (using knex.js)?

我正在尝试注册用户。过程如下——我先为用户生成哈希,然后生成令牌。假设这两个步骤成功,然后我将用户添加到数据库中。

此步骤涉及将用户添加到 2 tables - 一个仅包含哈希的 user_credentials table,并使用此操作后返回的 ID 添加其他用户详细信息和令牌给用户 table.

我能够成功添加用户 - 但是,当我在将用户添加到两个 table 后尝试访问 knex 返回的用户数据时,我总是得到 Data: undefined

不确定从 createUser() 发回行数据并使其在下一个 then 块(控制台记录的位置)中可用的正确方法是什么。

const handleRegister = (req, res, db, bcrypt, saltRounds) => {
    // Get the details from the body
    let user = req.body;
    // Hash the plain text password using bcrypt
    bcrypt.hash(user.password, saltRounds)
        .then((hash) => {
            delete user.password;
            // set user's hash to encrypted pw
            user.hash = hash; 
        })
        // Create token to be sent back to the client to create a session
        .then(() => createToken())
        // Set user's token to created token
        .then((token)=> {
            user.token = token;
        })
        // Save hashed password to db for the user and save user data to db with created token
        .then(() => createUser(user, db))
        // Return info of created user
        .then((data) => {
            delete user.hash;
            console.log("User:", user);
            console.log("Data:", data);
            res.status(201).json(user);
        })
        .catch((err) => {
            console.log("This was the error:", err);
            res.status(400).json("Something went wrong");
        });
}


// creating a user in the database
const createUser = (user, db) => {
    return db.transaction((trx) => {
        trx.insert({
            hash: user.hash
        })
        .into('user_credentials')
        .returning('id')
        .then((userId) => {
            return trx('users')
                .returning('*')
                .insert({
                    user_id: userId[0],
                    email: user.email,
                    name: user.name,
                    token: user.token,
                    created_at: new Date()
                });
        })
        .then((data)=> {
            return trx.commit()
            .then(() => data);
        })
        .catch((err) => {
            trx.rollback();
            throw err;
        })
    })
}

我认为问题出在你真正坚持的 user 对象上。

// Get the details from the body
let user = req.body;
// Hash the plain text password using bcrypt
bcrypt.hash(user.password, saltRounds)
    .then((hash) => {
        delete user.password;
        // set user's hash to encrypted pw
        user.hash = hash;
    })
    // Create token to be sent back to the client to create a session
    .then(() => createToken())
    // Set user's token to created token
    .then((token) => {
        user.token = token;
    })
    // Save hashed password to db for the user and save user data to db with created token
    // DOES THIS USER REALLY HAVE THE token AND hash? 
    .then(() => createUser(user, db))

您有一个从 req.body 创建的 user 实例,并使用哈希和令牌更新它。问题是您没有在创建令牌后 return 更新的 user 实例(带有哈希)。由于 promises 是异步的,您无法确保您确实在处理更新后的实例。因此,您可能会处理过时的实例。

我想你可以开始操作一个新的用户实例。

let user = req.body;
bcrypt.hash(user.password, saltRounds)
    .then((hash) => {
        delete user.password;
        user.hash = hash;
        return user
    })
    .then((user) => {
        user.token = createToken()
        return user
    })
    .then((user) => createUser(user, db)) // Create User with a really updated instance of user

我想你可以开始了

OK,睡了一觉,似乎找到了解决办法。

db.transaction 似乎创建了一个未决承诺,该承诺要么被 trx.commit 解决,要么被 trx.rollback 拒绝。因此,需要将包含提交和回滚的整个事务视为一个块,然后 then 块在成功插入后返回数据行。请参阅下面的代码。

如果有人想了解更多,请参考 - https://github.com/tgriesser/knex/issues/1346 http://knexjs.org/#Transactions

const createUser = (user, db) => {
    return db.transaction((trx) => {
        trx.insert({
            hash: user.hash
        })
        .into('user_credentials')
        .returning('id')
        .then((userId) => {
            return trx('users')
                .returning('*')
                .insert({
                    user_id: userId[0],
                    email: user.email,
                    name: user.name,
                    token: user.token,
                    created_at: new Date()
                });
        })
        .then(trx.commit)
        .catch((err) => {
            trx.rollback();
            throw err;
        })
    })
//Return the data here instead of along with trx.commit
    .then((data) => {
        return data;
    })
    .catch((err) => {
        console.log(err);
    });
}