sequelize: Using underscored: true still returns attributes in camelCase
What are you doing?
I have a project that uses Sequelize as ORM. I need the attribute names returned in snake_case
, but although I’ve specified underscored: true
in my model definition, the attributes are returned in camelCase
instead. (The DB tables are in snake_case
, as expected).
I’m also using Sequelize 4.x in a few other projects and it doesn’t affect it afaik.
Can be the same reason as here: https://github.com/sequelize/sequelize/issues/10581 (but it was closed because of not proper issue format).
I can provide more details if needed.
Sequelize config:
const Sequelize = require('sequelize');
const getSequelize = () => new Sequelize(config.postgres.database, config.postgres.username, config.postgres.password, {
host: config.postgres.host,
port: config.postgres.port,
dialect: 'postgres',
logging: sql => logger.debug(sql)
});
let sequelize = getSequelize();
exports.sequelize = sequelize;
exports.Sequelize = Sequelize;
Model definition
const { Sequelize, sequelize } = require('../lib/sequelize');
const Code = sequelize.define('code', {
value: {
type: Sequelize.STRING,
allowNull: false,
defaultValue: '',
validate: {
notEmpty: { msg: 'Code should be set.' },
},
},
integration_id: {
type: Sequelize.INTEGER,
allowNull: false,
defaultValue: '',
validate: {
notEmpty: { msg: 'Integration ID should be set.' },
},
},
claimed_by: {
type: Sequelize.INTEGER
}
}, { underscored: true, tableName: 'codes' });
module.exports = Code;
Endpoint using this model (I have 2 models but I provide only one for the case of simplicity):
exports.getMyCodes = async (req, res) => {
const myCodes = await Code.findAll({
where: {
claimed_by: req.user.id
},
include: [Integration],
order: [
['updated_at', 'DESC'],
]
});
return res.json(myCodes);
};
What do you expect to happen?
Everything returned in snake_case
What is actually happening?
The server response (note the integrationId
, createdAt
and updatedAt
are in camelCase
):
[{
"id": 7,
"value": "2",
"integration_id": 2,
"claimed_by": 1,
"createdAt": "2019-04-28T19:14:51.641Z",
"updatedAt": "2019-04-28T19:16:24.259Z",
"integrationId": 2,
"integration": {
"id": 2,
"name": "Help",
"code": "flixbus",
"quota_period": "month",
"quota_amount": 3,
"description": "**I need somebody**",
"createdAt": "2019-04-28T19:14:15.164Z",
"updatedAt": "2019-04-28T19:14:15.164Z"
}
}, {
"id": 6,
"value": "1",
"integration_id": 2,
"claimed_by": 1,
"createdAt": "2019-04-28T19:14:51.641Z",
"updatedAt": "2019-04-28T19:14:55.130Z",
"integrationId": 2,
"integration": {
"id": 2,
"name": "Help",
"code": "flixbus",
"quota_period": "month",
"quota_amount": 3,
"description": "**I need somebody**",
"createdAt": "2019-04-28T19:14:15.164Z",
"updatedAt": "2019-04-28T19:14:15.164Z"
}
}, {
"id": 1,
"value": "one",
"integration_id": 1,
"claimed_by": 1,
"createdAt": "2019-04-28T19:01:07.660Z",
"updatedAt": "2019-04-28T19:12:03.643Z",
"integrationId": 1,
"integration": {
"id": 1,
"name": "test",
"code": "test",
"quota_period": "month",
"quota_amount": 1,
"description": "test",
"createdAt": "2019-04-28T19:01:01.724Z",
"updatedAt": "2019-04-28T19:01:01.724Z"
}
}]
It only affects Sequelize 5.x, not 4.x
I’ve tried to downgrade to sequelize and sequelize-cli 4.x, and it works as expected:
$ npm ls | grep sequelize
├─┬ sequelize@4.43.2
├─┬ sequelize-cli@4.1.1
and the server response (with the exact same example above, only thing changed was downgrading sequelize
and sequelize-cli
packages) looks like this:
[{
"id": 8,
"value": "3",
"integration_id": 2,
"claimed_by": 1,
"created_at": "2019-04-28T19:14:51.641Z",
"updated_at": "2019-04-29T16:52:31.198Z",
"integration": {
"id": 2,
"name": "Help",
"code": "flixbus",
"quota_period": "month",
"quota_amount": 3,
"description": "**I need somebody**",
"created_at": "2019-04-28T19:14:15.164Z",
"updated_at": "2019-04-28T19:14:15.164Z"
}
}]
Environment
Dialect: postgres, also can be that it affects all of them. Dialect library version: pg 7.10.0 Database version: psql 10 Sequelize version: 5.7.6 Node Version: 10.2.1 OS: MacOS Mojave 10.14.4 (x64) Tested with latest release: yes, with 5.7.6 (latest NPM release afaik)
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 35
- Comments: 56 (4 by maintainers)
Hello, I was having the same problem as @twistedrc1017 with the timestamps
created_ at
andupdated_at
.The timestamps fields were both defined as snake case in the model:
And both undescored and undesrcoredAll were set to
true
in my database configuration file:But I was still getting cameCase timestamps in my responses:
To get my timestamps to snake case I set the following values to createdAt:‘created_at’ and the updatedAt:‘updated_at’ in my database config (as said in the docs If you want sequelize to handle timestamps, but only want some of them, or want your timestamps to be called something else, you can override each column individually ):
Then I got my timestamps in snake case:
All other fields were already being converted from camelCase to snake case and coming back in response as snake case. The only fields that were coming in response as camelCase were the two timestamps mentioned, the configuration helped solve my issue, I hope it helps you too! 😬
My grandchildren have already gone to school. But this error has still not fixed.
I’ve just upgraded from version 4 to 5.21.5. It looks like
underscored: true
no longer honors foreign key conventions. For example, I had to explicitly addforeignKey
to make this work the way it used to:If I don’t call it out it becomes
featureId
.I only recently upgraded to 5.x, so it is definitely a bug in V5 as you’ve just proven by downgrading. Hope this can be fixed ASAP.
It’s a bug and It should be fixed. As it’s not a good idea to use 2 different cases for the field names.
i am also experiencing this on v5.10.1
it seems fine when i look at my db with pgAdmin though:
Version 6.x seems to be affected as well.
Almost same issue here: I use underscored: true & timestamps: true, and I expect
created_at
,updated_at
fields in snake_case, as it was on sequelize@4. But after upgrading to sequelize@5 fields becomescreatedAt
andupdatedAt
@miladmeidanshahi Thanks!
For clarity’s sake, in the following text when I say:
So by default Sequelize will generate camelCase attributes and snake_case column (actually that second part is not the default yet) names because we consider it to be the standard naming conventions of JS & SQL respectively.
The
underscored
option is only used to generate snake_case column names. As others have found out in this thread, it has no impact on attribute names.For timestamp attributes, the solution is simple enough. You can configure it per-model using the 3 timestamp options:
Or configure them for every model by configuring the Sequelize instance itself:
For foreign keys, it’s trickier. There is a way to configure it per-model but there is no system wide configuration option.
To automatically generate a snake_case foreign key attribute names would require the return of an option like
underscoredAll
(but with a better name).If a way to tell sequelize to generate attributes in snake_case is the desired solution, I’ll keep this closed in favor of https://github.com/sequelize/sequelize/issues/11225 as it seems to be the relevant thread.
Let me know what you think 😃
Edit:
I also think the following two RFC are relevant, at least somewhat:
Thanks @dzvid your configuration worked for me:
https://sequelize.org/master/manual/naming-strategies.html
I’ve also noticed this issue (6.3.5). Any updates?
I have the same or similar issue with sequelize v5 and postgres. My schema is smaller so I’m seing this duplication only on xxxxx_id fields (and all of them are relations). Here are few examples:
Executing (default): SELECT "users"."id", "users"."username", "users"."password_hash", "users"."account_id", "users"."account_id" AS "accountId", "account"."id" AS "account.id", "account"."name" AS "account.name", "account"."token_balance" AS "account.token_balance" FROM "users" AS "users" LEFT OUTER JOIN "account" AS "account" ON "users"."account_id" = "account"."id" WHERE "users"."account_id" = 1 LIMIT 1;
Executing (default): SELECT "id", "username", "password_hash", "account_id", "account_id" AS "accountId" FROM "users" AS "users" WHERE "users"."id" = 1;
this one shows that the ‘camel-ization’ happens only on the root entity table (request_log) while the JOIN-ed table is not affected (see report_request.account_id)
Executing (default): SELECT "request_log"."id", "request_log"."report_request_id", "request_log"."report_request_id" AS "reportRequestId", "request_log"."ts", "request_log"."user_id", "report_request"."id" AS "report_request.id", "report_request"."account_id" AS "report_request.account_id", "report_request"."was_billed" AS "report_request.was_billed", "report_request"."exec_ts" AS "report_request.exec_ts", "report_request"."ttl_ts" AS "report_request.ttl_ts", "report_request"."balance_snapshot" AS "report_request.balance_snapshot" FROM "request_log" AS "request_log" LEFT OUTER JOIN "report_request" AS "report_request" ON "request_log"."report_request_id" = "report_request"."id" WHERE "request_log"."user_id" = '1' ORDER BY "request_log"."ts" DESC LIMIT '10' OFFSET '0';
Great, what you said is the root cause (
underscored: true
no longer honors foreign key conventions). You helped me, thanks. But, can anyone solve this problem?I think it’s worth noting that based on the current documentation, this is not a bug at all but instead a fundamental change to how it works:
https://sequelize.org/master/manual/naming-strategies.html
Which is great if I’m starting a new project from scratch. I think fully camelCased Javascript field names is a great convention; but it causes real problems when upgrading older Sequelize projects where we expect our Javascript attributes in snake_case. As mentioned above, this can be mitigated by explicitly setting any autogenerated fields like
createdAt: 'created_at'
.But I wouldn’t expect there to ever be a “fix” since it now matches up with their documentation.
It’s just hilarious. Fortunately, only after 20 mins of struggling I’ve realized that’s this was not my fault. ^6.3.5 confirmed bug.
this error still appear on version 6.3.4 I’ve added
underscore: true
for each model but still doesn’t work@papb any idea when this bug will be fixed?
option
underscored: true
affected on database column names, after find quarry still is camel case.hey guys . it’s still not working . i have create_at in migration and used underscored: true in my models but it’s not working
I’ve recently understood why it’s failing. Each model has an
attributes
object, where the keys are thecamelCase
attributes names, and each of these objects has afield
field which is asnake_case
orcamelCase
(depending on ifunderscored
istrue
orfalse
).Here is where the
field
field is set based onunderscored
option:https://github.com/sequelize/sequelize/blob/30c5ca5e127474f585388a9f26aefc06024fe2ec/lib/model.js#L1134
In the
findAll()
method where the options object for SQL query is constructed, it usesObject.keys(this.rawAttributes)
which will take the names incamelCase
disregarding theunderscored
option, here: https://github.com/sequelize/sequelize/blob/30c5ca5e127474f585388a9f26aefc06024fe2ec/lib/model.js#L1732If I change it to
Object.keys(this.rawAttributes).map(key => this.rawAttributes[key].field)
it should work. However it won’t turn includes attributes tosnake_case
.I’ll most like make a PR on this either this or next week, if somebody will be faster then me I’d really appreciate it!
Unfortunately I don’t have the time or means to get other dialects setup at the moment.
I am seeing the same problem. My issue seems to be that only association/foreign key variables are not becoming snake_case (same as #10581).