Return 来自 sequelize with association 的平面对象
Return flat object from sequelize with association
我正在努力在 sequelize 中转换我的所有查询。
我遇到的问题是,当 select 查询包含关联(例如一对多)时,我得到的对象是一个嵌套对象数组。
它看起来像:
[
{
"field1": "someval",
"field2": "someval1",
"assoc_table": {
"field_a": 1,
"field_b": "someval"
}
},
{
"field1": "someval",
"field2": "someval3",
"assoc_table": {
"field_a": 5,
"field_b": "someval"
}
},
{
"field1": "someval",
"field2": "someval3",
"assoc_table": {
"field_a": 12,
"field_b": "someval"
}
}
]
我尝试使用不同的模块来展平对象(在一个循环内,每个对象单独),但我总是收到一个错误,告诉我我试图展平的不仅仅是对象。
此外,我更希望避免对象被展平的部分,并通过 sequelize 简单地获得平坦的结果。
sequelize 代码如下所示:
models.table1.findAll({
attributes: ['field1', 'field2'],
where: {field1: someval},
include: [{model: models.assoc_table, required: true, attributes:['field_a', 'field_b']}]
}).then(function (result) {
res.send(result);
}).catch(function(error) {
console.log(error);
});
您的部分问题可能是您的 result
是一个模型实例数组,因此如果您没有对数组中的元素调用 toJSON
,您可能会遇到展平问题.我提供了可以使您的示例变平的代码:
result.forEach(obj => {
Object.keys(obj.toJSON()).forEach(k => {
if (typeof obj[k] === 'object') {
Object.keys(obj[k]).forEach(j => obj[j] = obj[k][j]);
}
});
});
您还可以添加 raw: true
作为 findAll
的选项,这将使您的对象变平,但它看起来像这样:
[
{
"field1": "someval",
"field2": "someval1",
"assoc_table.field_a": 1,
"assoc_table.field_b": "someval"
},
...
]
使用raw: true
辅助函数可以简化return 键。这将确保没有值被覆盖,并提供一种方法来保留一些基于字符串的嵌套(例如 ID)。
/**
Simplify keys returned by a sequelize {raw: true} query. Makes sure no values
are over-written and gives a way to keep some of string-based nesting (IDs for
example).
@example result.map(r => trimKeys(r))
*/
function trimKeys(obj, deepin = ['id']) {
const keys = Object.keys(obj)
const ret = {}
for (var i = 0; i < keys.length; i++) {
const key = keys[i]
const keyParts = key.split('.')
let idx = 1
let newKey = keyParts[keyParts.length - idx]
while((ret[newKey] || deepin.find(d => newKey === d)) && idx >= 0) {
idx++
newKey = keyParts[keyParts.length - idx] + '.' + newKey
}
ret[newKey] = obj[key]
}
return ret
}
老问题,但由于我也尝试这样做并找到了不需要“之后”映射的纯续集解决方案,所以我想在此处添加它。因此,为了让自己 return 成为所需的对象格式,应该是这样的,其中 attributes
是根据 include
table 列的 return 值明确分配的]:
models.table1.findAll({
attributes: [
'field1',
'field2',
[sequelize.col('models.assoc_table.field_a'), 'field_a'], // Set key
[sequelize.col('models.assoc_table.field_b'), 'field_b'], // Set key
],
where: {field1: someval},
include: [
{model: models.assoc_table,
required: true,
attributes:[], // Explicitly do not send back nested key's
}
]
})
老问题,但有了新的续集更新,同时使用:
raw:true,
nest:true
我正在努力在 sequelize 中转换我的所有查询。 我遇到的问题是,当 select 查询包含关联(例如一对多)时,我得到的对象是一个嵌套对象数组。
它看起来像:
[
{
"field1": "someval",
"field2": "someval1",
"assoc_table": {
"field_a": 1,
"field_b": "someval"
}
},
{
"field1": "someval",
"field2": "someval3",
"assoc_table": {
"field_a": 5,
"field_b": "someval"
}
},
{
"field1": "someval",
"field2": "someval3",
"assoc_table": {
"field_a": 12,
"field_b": "someval"
}
}
]
我尝试使用不同的模块来展平对象(在一个循环内,每个对象单独),但我总是收到一个错误,告诉我我试图展平的不仅仅是对象。
此外,我更希望避免对象被展平的部分,并通过 sequelize 简单地获得平坦的结果。
sequelize 代码如下所示:
models.table1.findAll({
attributes: ['field1', 'field2'],
where: {field1: someval},
include: [{model: models.assoc_table, required: true, attributes:['field_a', 'field_b']}]
}).then(function (result) {
res.send(result);
}).catch(function(error) {
console.log(error);
});
您的部分问题可能是您的 result
是一个模型实例数组,因此如果您没有对数组中的元素调用 toJSON
,您可能会遇到展平问题.我提供了可以使您的示例变平的代码:
result.forEach(obj => {
Object.keys(obj.toJSON()).forEach(k => {
if (typeof obj[k] === 'object') {
Object.keys(obj[k]).forEach(j => obj[j] = obj[k][j]);
}
});
});
您还可以添加 raw: true
作为 findAll
的选项,这将使您的对象变平,但它看起来像这样:
[
{
"field1": "someval",
"field2": "someval1",
"assoc_table.field_a": 1,
"assoc_table.field_b": "someval"
},
...
]
使用raw: true
辅助函数可以简化return 键。这将确保没有值被覆盖,并提供一种方法来保留一些基于字符串的嵌套(例如 ID)。
/**
Simplify keys returned by a sequelize {raw: true} query. Makes sure no values
are over-written and gives a way to keep some of string-based nesting (IDs for
example).
@example result.map(r => trimKeys(r))
*/
function trimKeys(obj, deepin = ['id']) {
const keys = Object.keys(obj)
const ret = {}
for (var i = 0; i < keys.length; i++) {
const key = keys[i]
const keyParts = key.split('.')
let idx = 1
let newKey = keyParts[keyParts.length - idx]
while((ret[newKey] || deepin.find(d => newKey === d)) && idx >= 0) {
idx++
newKey = keyParts[keyParts.length - idx] + '.' + newKey
}
ret[newKey] = obj[key]
}
return ret
}
老问题,但由于我也尝试这样做并找到了不需要“之后”映射的纯续集解决方案,所以我想在此处添加它。因此,为了让自己 return 成为所需的对象格式,应该是这样的,其中 attributes
是根据 include
table 列的 return 值明确分配的]:
models.table1.findAll({
attributes: [
'field1',
'field2',
[sequelize.col('models.assoc_table.field_a'), 'field_a'], // Set key
[sequelize.col('models.assoc_table.field_b'), 'field_b'], // Set key
],
where: {field1: someval},
include: [
{model: models.assoc_table,
required: true,
attributes:[], // Explicitly do not send back nested key's
}
]
})
老问题,但有了新的续集更新,同时使用:
raw:true,
nest:true