序列化嵌套关联查询

时间:2019-02-05 09:51:15

标签: sequelize.js sequelize-typescript

我有一个具有多个链接关联的模型,如下所示:

Epci -> have many ->公社-> have one ->出发的-> have one ->地区

我正在尝试检索Epci及其相关的Regions行,结果如下:

[
    {
        id: 1,
        name: 'EPCI 1',
        regions: [         // [1, 2] is also an acceptable format 
            { id: 1 },
            { id: 2 } 
        ]  
    }
]

目前,我取得了如下结果:

    [
        {
            id: 1,
            name: 'EPCI 1',
            communes: [         
                { 
                    id: 1, 
                    departement: {
                        id: 1,
                        region: {
                           id: 1
                        }  
                    } 
                },
                { 
                    id: 2, 
                    departement: {
                        id: 1,
                        region: {
                           id: 1
                        }  
                    } 
                },
                { 
                    id: 3, 
                    departement: {
                        id: 2,
                        region: {
                           id: 2
                        }  
                    } 
                },
            ]  
        }
    ]

通过此呼叫:

Epci.findAll({
    attributes: [
        'id',
        'name',
    ],
    include: [{
        model: Commune,
        attributes: ['id'],
        include: [{
            model: Departement,
            attributes: ['id'],
            include: [{
                model: Region,
                attributes: ['id'],
            }],
        }],
    }],
})

是否有一种使用Regions函数直接检索关联的(和不同的)findAll的方法?试图使用Virtual列和某种别名,但没有成功...

(我正试图避免对每个检索到的行运行查询)

当前的临时(?)解决方案(使用Sequelize TypeScript进行顺便说一句):

当前目标是检索一个简单的Regions数组,并清理Sequelize返回的“ communes”树属性的Epci结果。

因此,我们执行请求并检索所需的数据,然后使用Javascript转换结果。

Epci.findAll({
    attributes: [
        'id',
        'name',
    ],
    include: [{
        model: Commune,
        attributes: ['id'],
        include: [{
            model: Departement,
            attributes: ['id'],
            include: [{
                model: Region,
                attributes: ['id'],
            }],
        }],
    }],
}).map((row: Epci) => {
    // Retrieve plain object 
    const plain = row.get({ plain: true });

    // Rebuild (retreive, unique) the regions property (declared as Virtual in the Epci model -- important).
    plain.regions = plain.communes.map(commune => {
        return commune.departement.region.id;
    }).filter((id, index, self) => {
        return self.indexOf(id) === index;
    });
    // Remove the communes property.
    delete plain.communes;

    // Rebuild Epci instance with the modified plain object
    const instance = this.repository.build(plain);

    // Then return instance 
    return instance;
});

使用Postgresql数组函数的公认且高效的解决方案:

sequelize.query(`
    SELECT 
        E.id,
        E.name,
        ARRAY_AGG(DISTINCT R.id) as "regions"
    FROM layer_epci E
    LEFT JOIN layer_commune C ON C.epci_id = E.id
    LEFT JOIN layer_departement D ON C.departement_id= D.id
    LEFT JOIN layer_region R ON D.region_id = R.id
    GROUP BY E.id
`, {
   model: Epci,
   mapToModel: true
}).map((row: Epci) => {
    // Do some crazy stuff with Epci models.
    return epci;
});

0 个答案:

没有答案