1"use strict";(globalThis.webpackChunk=globalThis.webpackChunk||[]).push([[2831],{9072(e,n,i){i.r(n),i.d(n,{assets:()=>r,contentTitle:()=>t,default:()=>h,frontMatter:()=>l,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"other-topics/naming-strategies","title":"Naming Strategies","description":"The underscored option","source":"@site/versioned_docs/version-6.x.x/other-topics/naming-strategies.md","sourceDirName":"other-topics","slug":"/other-topics/naming-strategies","permalink":"/docs/v6/other-topics/naming-strategies","draft":false,"unlisted":false,"editUrl":"https://github.com/sequelize/website/tree/main/versioned_docs/version-6.x.x/other-topics/naming-strategies.md","tags":[],"version":"6.x.x","lastUpdatedBy":"renovate[bot]","lastUpdatedAt":1775795365000,"frontMatter":{"title":"Naming Strategies"},"sidebar":"tutorialSidebar","previous":{"title":"Migrations","permalink":"/docs/v6/other-topics/migrations"},"next":{"title":"Optimistic Locking","permalink":"/docs/v6/other-topics/optimistic-locking"}}');var a=i(74848),o=i(28453);const l={title:"Naming Strategies"},t=void 0,r={},d=[{value:"The <code>underscored</code> option",id:"the-underscored-option",level:2},{value:"Singular vs. Plural",id:"singular-vs-plural",level:2},{value:"When defining models",id:"when-defining-models",level:3},{value:"When defining a reference key in a model",id:"when-defining-a-reference-key-in-a-model",level:3},{value:"When retrieving data from eager loading",id:"when-retrieving-data-from-eager-loading",level:3},{value:"Overriding singulars and plurals when defining aliases",id:"overriding-singulars-and-plurals-when-defining-aliases",level:3}];function c(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(n.h2,{id:"the-underscored-option",children:["The ",(0,a.jsx)(n.code,{children:"underscored"})," option"]}),"\n",(0,a.jsxs)(n.p,{children:["Sequelize provides the ",(0,a.jsx)(n.code,{children:"underscored"})," option for a model. When ",(0,a.jsx)(n.code,{children:"true"}),", this option will set the ",(0,a.jsx)(n.code,{children:"field"})," option on all attributes to the ",(0,a.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Snake_case",children:"snake_case"})," version of its name. This also applies to foreign keys automatically generated by associations and other automatically generated fields. Example:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const User = sequelize.define(\n 'user',\n { username: Sequelize.STRING },\n {\n underscored: true,\n },\n);\nconst Task = sequelize.define(\n 'task',\n { title: Sequelize.STRING },\n {\n underscored: true,\n },\n);\nUser.hasMany(Task);\nTask.belongsTo(User);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Above we have the models User and Task, both using the ",(0,a.jsx)(n.code,{children:"underscored"})," option. We also have a One-to-Many relationship between them. Also, recall that since ",(0,a.jsx)(n.code,{children:"timestamps"})," is true by default, we should expect the ",(0,a.jsx)(n.code,{children:"createdAt"})," and ",(0,a.jsx)(n.code,{children:"updatedAt"})," fields to be automatically created as well."]}),"\n",(0,a.jsxs)(n.p,{children:["Without the ",(0,a.jsx)(n.code,{children:"underscored"})," option, Sequelize would automatically define:"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:["A ",(0,a.jsx)(n.code,{children:"createdAt"})," attribute for each model, pointing to a column named ",(0,a.jsx)(n.code,{children:"createdAt"})," in each table"]}),"\n",(0,a.jsxs)(n.li,{children:["An ",(0,a.jsx)(n.code,{children:"updatedAt"})," attribute for each model, pointing to a column named ",(0,a.jsx)(n.code,{children:"updatedAt"})," in each table"]}),"\n",(0,a.jsxs)(n.li,{children:["A ",(0,a.jsx)(n.code,{children:"userId"})," attribute in the ",(0,a.jsx)(n.code,{children:"Task"})," model, pointing to a column named ",(0,a.jsx)(n.code,{children:"userId"})," in the task table"]}),"\n"]}),"\n",(0,a.jsxs)(n.p,{children:["With the ",(0,a.jsx)(n.code,{children:"underscored"})," option enabled, Sequelize will instead define:"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:["A ",(0,a.jsx)(n.code,{children:"createdAt"})," attribute for each model, pointing to a column named ",(0,a.jsx)(n.code,{children:"created_at"})," in each table"]}),"\n",(0,a.jsxs)(n.li,{children:["An ",(0,a.jsx)(n.code,{children:"updatedAt"})," attribute for each model, pointing to a column named ",(0,a.jsx)(n.code,{children:"updated_at"})," in each table"]}),"\n",(0,a.jsxs)(n.li,{children:["A ",(0,a.jsx)(n.code,{children:"userId"})," attribute in the ",(0,a.jsx)(n.code,{children:"Task"})," model, pointing to a column named ",(0,a.jsx)(n.code,{children:"user_id"})," in the task table"]}),"\n"]}),"\n",(0,a.jsxs)(n.p,{children:["Note that in both cases the fields are still ",(0,a.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Camel_case",children:"camel
1Case"})," in the JavaScript side; this option only changes how these fields are mapped to the database itself. The ",(0,a.jsx)(n.code,{children:"field"})," option of every attribute is set to their snake_case version, but the attribute itself remains camelCase."]}),"\n",(0,a.jsxs)(n.p,{children:["This way, calling ",(0,a.jsx)(n.code,{children:"sync()"})," on the above code will generate the following:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'CREATE TABLE IF NOT EXISTS "users" (\n "id" SERIAL,\n "username" VARCHAR(255),\n "created_at" TIMESTAMP WITH TIME ZONE NOT NULL,\n "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL,\n PRIMARY KEY ("id")\n);\nCREATE TABLE IF NOT EXISTS "tasks" (\n "id" SERIAL,\n "title" VARCHAR(255),\n "created_at" TIMESTAMP WITH TIME ZONE NOT NULL,\n "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL,\n "user_id" INTEGER REFERENCES "users" ("id") ON DELETE SET NULL ON UPDATE CASCADE,\n PRIMARY KEY ("id")\n);\n'})}),"\n",(0,a.jsx)(n.h2,{id:"singular-vs-plural",children:"Singular vs. Plural"}),"\n",(0,a.jsx)(n.p,{children:"At a first glance, it can be confusing whether the singular form or plural form of a name shall be used around in Sequelize. This section aims at clarifying that a bit."}),"\n",(0,a.jsxs)(n.p,{children:["Recall that Sequelize uses a library called ",(0,a.jsx)(n.a,{href:"https://www.npmjs.com/package/inflection",children:"inflection"})," under the hood, so that irregular plurals (such as ",(0,a.jsx)(n.code,{children:"person -> people"}),") are computed correctly. However, if you're working in another language, you may want to define the singular and plural forms of names directly; sequelize allows you to do this with some options."]}),"\n",(0,a.jsx)(n.h3,{id:"when-defining-models",children:"When defining models"}),"\n",(0,a.jsx)(n.p,{children:"Models should be defined with the singular form of a word. Example:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"sequelize.define('foo', { name: DataTypes.STRING });\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Above, the model name is ",(0,a.jsx)(n.code,{children:"foo"})," (singular), and the respective table name is ",(0,a.jsx)(n.code,{children:"foos"}),", since Sequelize automatically gets the plural for the table name."]}),"\n",(0,a.jsx)(n.h3,{id:"when-defining-a-reference-key-in-a-model",children:"When defining a reference key in a model"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"sequelize.define('foo', {\n name: DataTypes.STRING,\n barId: {\n type: DataTypes.INTEGER,\n allowNull: false,\n references: {\n model: 'bars',\n key: 'id',\n },\n onDelete: 'CASCADE',\n },\n});\n"})}),"\n",(0,a.jsxs)(n.p,{children:["In the above example we are manually defining a key that references another model. It's not usual to do this, but if you have to, you should use the table name there. This is because the reference is created upon the referenced table name. In the example above, the plural form was used (",(0,a.jsx)(n.code,{children:"bars"}),"), assuming that the ",(0,a.jsx)(n.code,{children:"bar"})," model was created with the default settings (making its underlying table automatically pluralized)."]}),"\n",(0,a.jsx)(n.h3,{id:"when-retrieving-data-from-eager-loading",children:"When retrieving data from eager loading"}),"\n",(0,a.jsxs)(n.p,{children:["When you perform an ",(0,a.jsx)(n.code,{children:"include"})," in a query, the included data will be added to an extra field in the returned objects, according to the following rules:"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:["When including something from a single association (",(0,a.jsx)(n.code,{children:"hasOne"})," or ",(0,a.jsx)(n.code,{children:"belongsTo"}),") - the field name will be the singular version of the model name;"]}),"\n",(0,a.jsxs)(n.li,{children:["When including something from a multiple association (",(0,a.jsx)(n.code,{children:"hasMany"})," or ",(0,a.jsx)(n.code,{children:"belongsToMany"}),") - the field name will be the plural form of the model."]}),"\n"]}),"\n",(0,a.jsx)(n.p,{children:"In short, the name of the field will take the most logical form in each situation."}),"\n",(0,a.jsx)(n.p,{children:"Examples:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"// Assuming Foo.hasMany(Bar)\nconst foo = Foo.findOne({ include: Bar });\n// foo.bars will be an array\n// foo.bar will not exist since it doens't make sense\n\n// Assuming Foo.hasOne(Bar)\nconst foo = Foo.findOne({ include: Bar });\n// foo.bar will be an object (possibly null if there is no associated model)\n// foo.bars will not exist since it doens't make sense\n\n// And so on.\n"})}),"\n",(0,a.jsx)(n.h3,{id:"overriding-singulars-and-plurals-when-defining-aliases",children:"Overriding singulars and plurals when defining aliases"}),"\n",(0,a.jsxs)(n.p,{children:["When defining an alias for an association, instead of using simply ",(0,a.jsx)(n.code,{children:"{ as: 'myAlias' }"}),", you can pass an object to specify the singular and plural forms:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"Project.belongsToMany(User, {\n as: {\n singular: 'l\xedder',\n plural: 'l\xedderes',\n },\n});\n"})}),"\n",(0,a.jsx)(n.p,{children:"If you know that a model will always use the same alias in associations, you can provide the singular and plural forms directly to the model itself:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const User = sequelize.define(\n 'user',\n {\n /* ... */\n }
1,\n {\n name: {\n singular: 'l\xedder',\n plural: 'l\xedderes',\n },\n },\n);\nProject.belongsToMany(User);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The mixins added to the user instances will use the correct forms. For example, instead of ",(0,a.jsx)(n.code,{children:"project.addUser()"}),", Sequelize will provide ",(0,a.jsx)(n.code,{children:"project.getL\xedder()"}),". Also, instead of ",(0,a.jsx)(n.code,{children:"project.setUsers()"}),", Sequelize will provide ",(0,a.jsx)(n.code,{children:"project.setL\xedderes()"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:["Note: recall that using ",(0,a.jsx)(n.code,{children:"as"})," to change the name of the association will also change the name of the foreign key. Therefore it is recommended to also specify the foreign key(s) involved directly in this case."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"// Example of possible mistake\nInvoice.belongsTo(Subscription, { as: 'TheSubscription' });\nSubscription.hasMany(Invoice);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The first call above will establish a foreign key called ",(0,a.jsx)(n.code,{children:"theSubscriptionId"})," on ",(0,a.jsx)(n.code,{children:"Invoice"}),". However, the second call will also establish a foreign key on ",(0,a.jsx)(n.code,{children:"Invoice"})," (since as we know, ",(0,a.jsx)(n.code,{children:"hasMany"})," calls places foreign keys in the target model) - however, it will be named ",(0,a.jsx)(n.code,{children:"subscriptionId"}),". This way you will have both ",(0,a.jsx)(n.code,{children:"subscriptionId"})," and ",(0,a.jsx)(n.code,{children:"theSubscriptionId"})," columns."]}),"\n",(0,a.jsxs)(n.p,{children:["The best approach is to choose a name for the foreign key and place it explicitly in both calls. For example, if ",(0,a.jsx)(n.code,{children:"subscription_id"})," was chosen:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"// Fixed example\nInvoice.belongsTo(Subscription, {\n as: 'TheSubscription',\n foreignKey: 'subscription_id',\n});\nSubscription.hasMany(Invoice, { foreignKey: 'subscription_id' });\n"})})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},28453(e,n,i){i.d(n,{R:()=>l,x:()=>t});var s=i(96540);const a={},o=s.createContext(a);function l(e){const n=s.useContext(o);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:l(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.