Sequelize association methods attribures - javascript

I have a struggle with associations method. I have users and lists with many to many association, so the sequelize generate for me method user.getLists(); But when I call that mehod result is
[
{
"id": 1,
"title": "Boop",
"created_at": "2018-08-15T14:53:51.276Z",
"updated_at": "2018-08-15T14:53:51.276Z",
"deleted_at": null,
"user_list": {
"owner": true,
"created_at": "2018-08-15T14:53:51.290Z",
"updated_at": "2018-08-15T14:53:51.290Z",
"deleted_at": null,
"user_id": 1,
"list_id": 1
}
}
]
And I can't find a way to remove user_list attribute from it or rename it.
Is there a way to remove this attribute on ORM level or rename it?
For example this is not working:
user.getLists({ attributes: ['id'] });
user.getLists({ attributes: [['user_list', 'random_name']] });
My models look like this
User model:
const user = db.define(
'user',
{
id: {
type: sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
email: {
type: sequelize.STRING,
unique: 'email_unique',
allowNull: false,
validate: {
isEmail: true,
},
},
});
List model:
const list = db.define(
'list',
{
id: {
type: sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
title: {
type: sequelize.STRING,
allowNull: false,
},
},
);
UserList:
const userList = db.define(
'user_list',
{
owner: {
type: sequelize.BOOLEAN,
allowNull: false,
},
},
);
Associations:
User.belongsToMany(
List,
{
through: UserList,
as: {
singular: 'List',
plural: 'Lists',
},
})
List.belongsToMany(User, { through: UserList });

Related

Sequlize How to make bulkCreate with associated table and not create new values if theay already exist in table

I Have 2 models. Actors And Movies, they have BelongsToMany Asscociation
const Movie = sequelize.define(
MOVIES,
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
title: {
type: DataTypes.STRING,
allowNull: false,
},
year: {
type: DataTypes.NUMBER,
allowNull: false,
},
format: {
type: DataTypes.ENUM,
values: [VHS, DVD, BLU_RAY],
allowNull: false,
},
},
{
indexes: [
{
unique: true,
fields: ['title'],
},
],
}
);
const Actor = sequelize.define(
ACTORS,
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
indexes: [
{
unique: true,
fields: ['name'],
},
],
}
);
and this logic:
const moviesData = req.files.movies.data.toString();
const newMovies = movieHelper.formatArrayOfMovieObjects(moviesData);
const movies = await Movie.bulkCreate(newMovies, {
include: {
model: Actor,
},
updateOnDuplicate: ['title'],
});
res.json(movies).status(200);
How to make to not create new records if movie.title exist in table
I tried updateOnDuplicate param but it give me this error: [Error: SQLITE_CONSTRAINT: FOREIGN KEY constraint failed
If your SQLite version supports unique constraints/indexes then you can create one indicating the title field and this way the option updateOnDuplicate should work well.

Sequelize with filter and association eager loading

I'm fairly new to using Sequelize and I'm having issues with findAndCountAll while using filters with eager loading. Following are the two models and their definitions.
const Campaign = sequelize.define(
"campaign",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.BIGINT,
},
name: {
type: Sequelize.STRING(512),
},
advertiser_id: {
type: Sequelize.BIGINT,
},
},
{
timestamps: true,
createdAt: "created_at",
updatedAt: "modified_at",
});
Campaign.associate = function (model) {
Campaign.hasMany(model.performanceData, {
as: "performanceData",
foreignKey: "campaign_id",
constraints: false,
});
};
const PerformanceData = sequelize.define(
"performanceData",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.BIGINT,
},
campaign_id: {
type: Sequelize.BIGINT,
},
clicks: {
type: Sequelize.BIGINT,
},
date: {
type: Sequelize.STRING(20),
},
},
{
tableName: "performance_data",
timestamps: true,
createdAt: "created_at",
updatedAt: "modified_at",
});
One campaign will have multiple performance data records based on date. I want to get all the campaigns by an advertiser (paginated) while eager loading the aggregate of performance data. So the performance data returned should be aggregate of a particular campaign.
Following is the query I'm using but it doesn't return the data:
const campaigns = await Campaign.findAndCountAll({
where: {
advertiser_id: reqObject.advertiser_id,
},
include: {
as: "performanceData",
model: PerformanceData,
attributes: [],
},
attributes: {
include: [
[
db.Sequelize.fn("SUM", db.Sequelize.col("performanceData.clicks")),
"clicks",
],
],
},
group: ["campaign.id"],
offset: reqObject.page,
limit: reqObject.size});
Can anyone please help with this?

How to Update a DataTypes.ENUM datatype in Sequelize

I have this sequelize model:
var TableName = sequelize.define(
"TableName",
{
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
name: { type: DataTypes.STRING, allowNull: false },
approvedTenure: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
},
status: {
type: DataTypes.ENUM,
values: ["PENDING", "YES", "NO", "DON'T KNOW"],
allowNull: false,
defaultValue: "PENDING",
},
narrative: { type: DataTypes.STRING, allowNull: false, defaultValue: "" },
},
{
timestamps: true,
tableName: "table_name",
freezeTableName: true,
}
);
And when I run the following code trying to update the table:
const data = {id: 23, status: "YES", narrative: "I am good", approvedTenure: 2}
async updateTable(data) {
return await TableName.update(
{
status: data.status,
narrative: data.narrative,
approvedTenure: data.approvedTenure,
},
{
where: { id: data.id },
returning: true,
}
);
}
The table gets updated except the status column with DataTypes.ENUM as the data type. How do I go about updating the status column with the DataTypes.ENUM data type?

How can I parse complex query operations using Sequelize.js?

I have an Option table which has a question_id as a foreign key to table Questions.
Then in Questions table I've 2 foreign keys namely question_category_id and section_id. For the 1st Option part I am able to apply LEFT OUTER JOIN query but also I need to fetch the values of Question_Category and Section table as well.
Let me first clear out how I want my output to be:
Output JSON
"questions": [
{
"id": 9,
"isActive": true,
"question_text": "What is abc ?",
"createdBy": "avis",
"questionCategory": {
"id": 1,
"name": "aptitude"
},
"section": {
"id": 1,
"marks": 5
},
"options": [
{
"id": 1,
"answer": true,
"option_text": "A",
"question_id": 9
},
{
"id": 2,
"answer": false,
"option_text": "B",
"question_id": 9
}
]
}
]
Now I am specifying my database models:
question_category.js
module.exports = (sequelize, Sequelize) => {
const QuestionCategory = sequelize.define('question_category', {
id:{ type: Sequelize.BIGINT, autoIncrement: true, allowNull: false, primaryKey: true },
isActive: { type: Sequelize.BOOLEAN, allowNull: false },
question_category_name: { type: Sequelize.STRING, allowNull: false },
createdBy: { type: Sequelize.STRING, allowNull: false },
createdAt: { type: Sequelize.DATE, allowNull: false, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }
}, { timestamps: false });
return QuestionCategory;
};
section.js
module.exports = (sequelize, Sequelize) => {
const Section = sequelize.define('section', {
id: { type: Sequelize.BIGINT, autoIncrement: true, allowNull: false, primaryKey: true },
isActive: { type: Sequelize.BOOLEAN, allowNull: false },
marks_per_question: { type: Sequelize.INTEGER, allowNull: false },
createdBy: { type: Sequelize.STRING, allowNull: false },
createdAt: { type: Sequelize.DATE, allowNull: false, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }
}, { timestamps: false });
return Section;
};
question.js
module.exports = (sequelize, Sequelize) => {
const Questions = sequelize.define('questions', {
id:{ type: Sequelize.BIGINT, autoIncrement: true, allowNull: false, primaryKey: true },
isActive: { type: Sequelize.BOOLEAN, allowNull: false },
question_text: { type: Sequelize.STRING, allowNull: false },
createdBy: { type: Sequelize.STRING, allowNull: false },
createdAt: { type: Sequelize.DATE, allowNull: false, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }
}, { timestamps: false });
return Questions;
};
option.js
module.exports = (sequelize, Sequelize) => {
const Options = sequelize.define('options', {
id:{ type: Sequelize.BIGINT, autoIncrement: true, allowNull: false, primaryKey: true },
answer: { type: Sequelize.BOOLEAN, allowNull: true },
option_text: { type: Sequelize.STRING, allowNull: false },
createdAt: { type: Sequelize.DATE, allowNull: false, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }
}, { timestamps: false });
return Options;
};
In the database.js i.e. the main js file for exporting the models I have associated the models like this:
const dbConfig = require('../config/db.config');
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD,
{
host: dbConfig.HOST,
port: dbConfig.PORT,
dialect: 'mysql',
operatorsAliases: 0
}
);
sequelize.authenticate().then(() => {
console.log('Connection has been established successfully.');
}).catch(err => {
console.error('Unable to connect to the database:', err);
});
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.QuestionCategory = require('./question_model/question_category')(sequelize, Sequelize);
db.Section = require('./question_model/section')(sequelize, Sequelize);
db.Question = require('./question_model/question')(sequelize, Sequelize);
db.Option = require('./question_model/option')(sequelize, Sequelize);
// Relating Question Category with Questions
db.QuestionCategory.hasMany(db.Question, {
foreignKey: 'question_category_id',
sourceKey: 'id'
});
db.Question.belongsTo(db.QuestionCategory, {
foreignKey: 'question_category_id',
targetKey: 'id'
});
// Relating Sections with Questions
db.Section.hasMany(db.Question, {
foreignKey: 'section_id',
sourceKey: 'id'
});
db.Question.belongsTo(db.Section, {
foreignKey: 'section_id',
targetKey: 'id'
});
// Relating Questions with Options
db.Question.hasMany(db.Option, {
foreignKey: 'question_id',
sourceKey: 'id'
});
db.Option.belongsTo(db.Question, {
foreignKey: 'question_id',
targetKey: 'id'
});
So this is my structure.
Now to achieve the above output format I've written the below logic but it's not outputting the correct JSON:
const db = require('../models/database');
const errors = require('../config/errors').errors;
exports.viewQuestion = (req, res, next) => {
try {
db.Question.findAll({
attributes: { exclude: ['createdAt','section_id','question_category_id'] },
include: [{
model: db.Option,
attributes: { exclude: ['createdAt'] }
}]
}).then(data => {
if(data.length == 0) {
return res.status(200).send({
status: 200,
questions: 'No Data'
});
}
db.QuestionCategory.findAll({
attributes: { exclude: ['createdBy','createdAt','isActive'] },
include: db.Question,
attributes: { exclude: ['id','isActive','question_text','createdBy','createdAt','section_id'] }
}).then(question_category => {
Object.assign(data[0], { 'questionCategories': question_category });
res.status(200).send({
status: 200,
questions: data
});
});
}).catch(err => {
return res.status(204).send(errors.MANDATORY_FIELDS);
});
} catch(err) {
return res.status(204).send(errors.MANDATORY_FIELDS);
}
};
I didn't wrote the logic for Section part yet as I was going Step by Step. The output that I am getting by writing this logic is:
{
"status": 200,
"questions": [
{
"id": 9,
"isActive": true,
"question_text": "What is abc ?",
"createdBy": "avis",
"options": [
{
"id": 1,
"answer": true,
"option_text": "A",
"question_id": 9
},
{
"id": 2,
"answer": false,
"option_text": "B",
"question_id": 9
}
]
}
]
}
The questionCategories didn't got reflected in the output.
Please help me out as I've more scenarios like this and all I can solve depending on this.
If you are using Sequelize to get objects from a DB via models then you should turn them into plain objects before adding some properties. For instance, if you get a collection of objects you should call get({ plain: true }) for each of them.
const plainObj = data[0].get({ plain: true })
Object.assign(plainObj, { 'questionCategories': question_category });
res.status(200).send({
status: 200,
questions: plainObj
});

Sequelize mixes camel case and snake case keys in result object

Am trying to get the resulting plain object from Sequelize create (or any Sequelize query) to be snake case keys throughout. The result objects are mixed however. Here's an example query:
const object = await models.Account.create({
userId,
name,
accountNumber
})
console.log(object.get({ plain: true }))
The result object is mixed keys of camel case and snake case:
{
"id": 2,
"userId": 1,
"name": "baller",
"accountNumber": "1234-123-1234",
"updated_at": "2019-01-07T02:23:41.305Z",
"created_at": "2019-01-07T02:23:41.305Z",
"balance": "0.00",
"deleted_at": null
}
Any idea how to get the result plain object or nested objects to be completely snake case keys only? Upgrade sequelize from ^4.42.0 to ^5.0.0-beta in package.json and happens for both. Not sure what else to try?
Accounts table is all snake case column names:
return queryInterface.createTable('accounts', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
user_id: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: 'users',
key: 'id'
}
},
name: {
allowNull: false,
type: Sequelize.STRING(50)
},
account_number: {
allowNull: false,
type: Sequelize.STRING(50)
},
Account model has has option underscored: true and camelCase attrs with field in snake case
const Account = sequelize.define('Account', {
userId: {
type: DataTypes.INTEGER,
field: 'user_id',
allowNull: false,
validate: {
notNull(value) {
if (value == null) {
throw new Error('Missing user id')
}
}
}
},
name: {
type: DataTypes.STRING,
field: 'name',
validate: {
notEmpty: true
}
},
accountNumber: {
type: DataTypes.STRING,
field: 'account_number',
validate: {
notEmpty: true
}
},
}, {
tableName: 'accounts',
paranoid: true,
underscored: true
})
For now I'm resolving it with:
import snakeCaseKeys from 'snakecase-keys'
let jsonObject = object.get({ plain: true })
jsonObject = snakeCaseKeys(jsonObject)

Categories

Resources