没有两个查询,我如何在Knex中做到这一点

问题描述

我想不使用两个查询来执行此搜索

app.db('users').where({
            id: req.userData.id
        }).first().then(result => {

            if (!result) {
                throw new CompleteError('Usuário não enconTrado.',404)
            }

            app.db('addresses').where({
                id: result.address_id
            }).first().then(address_result => {
                if (address_result) {
                    result.address = address_result
                    res.json(result)
                } else {
                    throw new CompleteError('Falha ao buscar endereço do usuário.',500)
                }
            }).catch(e => {
                return next(e)
            })

        }).catch(e => {
            return next(e)
        }) 

如果其中一项搜索失败或找不到任何寄存器,则搜索进度将停止并抛出错误。该数据库是postgresql。如果没有这种方法的替代方法,请帮助改善代码,我是入门开发人员,我需要您的意见。拜托,对不起我的英语。

结果必须是这样的:

{
  "id": 21,"name": "Sérgio","cpf": "11111111111","email": "sergio11@gmail.com","pass": "$2a$10$Jx7wAd3QSMFlkXi3g0eVOOoW8o65OgDZVQ7wTWuxquytVhUhrUf/.","phone": "5544313113131","last_access": "2020-08-11T10:14:20.207Z","created_at": "2020-08-11T10:14:20.207Z","deleted_at": null,"address_id": 21,"address": {
    "id": 21,"street": "Street Manu","number": "851","complement": "A","city": "Mari Hill","state": "Para","country": "Brazil","last_access": "2020-08-11T10:14:19.837Z","created_at": "2020-08-11T10:14:19.837Z","deleted_at": null
  }
}

解决方法

您可以使用JOIN执行此查询,然后重新排列结果。

您要查找的查询看起来像这样:

SELECT *
FROM users
    LEFT JOIN addresses ON addresses.id=users.address_id;

(我更熟悉MySQL / MariaDB,因此语法可能有所不同)。

LEFT JOIN意味着如果找到用户但没有找到地址,则地址列将为空。

这可以转换为以下Knex表达式:

app.db('users')
    .leftJoin('addresses','addresses.id','=','users.address_id')
    .select(
        'users.id','users.name','users.cpf','users.email','users.pass','users.phone','users.last_access','users.created_at','users.deleted_at','users.address_id','addresses.id AS addr_id','addresses.street AS addr_street','addresses.number AS addr_number','addresses.complement AS addr_complement','addresses.city AS addr_city','addresses.state AS addr_state','addresses.country AS addr_country','addresses.last_access AS addr_last_access','addresses.created_at AS addr_created_at','addresses.deleted_at AS addr_deleted_at'
    )
    .first()
    .then((result) => {
        // no result at all? no user found
        if (!result) {
            throw new CompleteError('Usuário não encontrado.',404);
        }

        // no addr_id? user found but not the address
        if (!result.addr_id) {
            throw new CompleteError('Falha ao buscar endereço do usuário.',500);
        }

        // result contains all the fields from BOTH tables as a flat object
        // you'll need to rearrange things
        return {
            // assign properties to new names...
            id: result.id,// and so on...
        };
    });

请注意,我已经在addresses调用中重命名了select()中的所有列。这是因为Knex不会在带有JOIN子句的查询中分配新的列名,除非您明确命名这些列,否则您将获得重复的列名(以及很多困惑)。