Those are my tables (not all columns included) and relationships
var client = schema.define('client', {
name: {
type: Sequelize.STRING,
allowNull: false
},
}
var task = schema.define('task', {
name: {
type: Sequelize.STRING,
unique: true,
allowNull: false
},
description: {
type: Sequelize.STRING,
}
}
var clientTask = schema.define('clientTask', {
value: {
type: Sequelize.STRING,
allowNull: false,
defaultValue: false
},
}
client.belongsToMany(task, { through: clientTask });
task.belongsToMany(client, { through: clientTask });
I want to get only name from task and value from clientTask, I searching by client id and here is what I tried so far.
client.findAll({
attributes: [],
where: {id: clientId},
include: [{
model: task,
attributes: ['name']
}]
}).then(function (clients) {
//client.tasks is array with task objects(models) with only name attribute
//client.tasks[0].clientTask is object(models) with all attributes but I want only `value`
}
Basically what I want is this query
Select
tasks.name,
clienttasks.value
From
clients Inner Join
clienttasks
On clienttasks.clientId = clients.id Inner Join
tasks
On clienttasks.taskId = tasks.id
Where clients.id = ?
You could query it like this
clients.findById(1, {
attributes: ['id'],
include: [{
model: tasks,
attributes: ['name'],
required: false
}]
}).then(function(client) {
return client.tasks.map(function(task) {
return {
name: task.name,
value: task.clients_tasks.value
};
});
}).then(function(result) {
console.log(result);
// The rest of you logic here...
});
Related
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.
I'm working on an API in Node.js with the Sequelize ORM.
I make an API route to retrieve a random question, it works one time out of three but often returns an empty array. I can't find a solution in the documentation to prevent this...
app.get('/:certifName/:levelName/random', async function (req, res) {
return await Certification.findOne(
{
attributes: ['id', 'label'],
include: [{
model: CertificationLevel,
as: "tcl",
required: true,
attributes: ['id', 'label', 'question_number', 'exam_duration'],
include: [{
attributes: ['id', 'label'],
model: CertificationChapter,
as: "tcc",
required: true,
limit: 1,
order: [ [ Sequelize.fn('RANDOM') ] ],
include: [{
model: Question,
as: "tq",
required: true,
include: [{
model: QuestionChoice,
as: "tqc",
required: false,
attributes: ['id', 'label_fr', 'is_answer'],
}],
}],
}],
where: { label: req.params.levelName }
}],
where: { label: req.params.certifName }
})
.then(data => {
if (data) {
res.send(data);
}
else
res.sendStatus(204);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Error retrieving certification details"
});
});
});
The last model :
module.exports =
class CertificationLevel extends Sequelize.Model {
static init(sequelize) {
return super.init(
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
label: Sequelize.STRING,
slug: Sequelize.STRING,
description: Sequelize.TEXT,
question_number: Sequelize.INTEGER,
exam_duration: Sequelize.INTEGER,
created_at: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
updated_at: Sequelize.DATE,
deleted_at: Sequelize.DATE
},
{
tableName: 't_certifications_levels',
sequelize,
underscored: true,
timestamps: false
},
);
}
static associate(models) {
this.belongsTo(models.Certification, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false,
name: "certification_id"
}
}),
this.hasMany(models.CertificationChapter, { as:'tcc', foreignKey: 'level_id' })
this.hasMany(models.Subscription, { as:'ts',foreignKey: 'level_id' })
}
}
And this is a SQL query generate :
SELECT "Certification".*,
"tcl"."id" AS "tcl.id",
"tcl"."label" AS "tcl.label",
"tcl"."question_number" AS "tcl.question_number",
"tcl"."exam_duration" AS "tcl.exam_duration"
FROM
(SELECT "Certification"."id",
"Certification"."label"
FROM "t_certifications" AS "Certification"
WHERE "Certification"."label" = 'ISTQB'
AND
(SELECT "tcl"."certification_id"
FROM "t_certifications_levels" AS "tcl"
WHERE ("tcl"."label" = 'Fondation'
AND "tcl"."certification_id" = "Certification"."id")
LIMIT 1) IS NOT NULL
LIMIT 1) AS "Certification"
INNER JOIN "t_certifications_levels" AS "tcl" ON "Certification"."id" = "tcl"."certification_id"
AND "tcl"."label" = 'Fondation';
I don't know why I have two executing to my route?
I am a real beginner in back development...
Thank for you help
I am not able to give relationship into to two tables User and Media
User have profile field which should contain Media Id.
Right now I have written these models User and Media now I want to fetch data using join query.
USER MODEL
const User = sequelize.sequelize.define('users', {
id: {
type: sequelize.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
firstName: {
type: sequelize.Sequelize.STRING
},
lastName: {
type: sequelize.Sequelize.STRING
},
email: {
type: sequelize.Sequelize.STRING
},
media_id: {
type: sequelize.Sequelize.INTEGER,
foreignKey: true
}
});
Media.belongsTo(User, {
as: 'media',
foreignKey: {
name: 'media_id',
allowNull: false
}
});
User.find({where: {}, include: [Media]})
User.sync();
MEDIA MODEL
const Media = sequelize.sequelize.define('media', {
id: {
type: sequelize.Sequelize.INTEGER,
primaryKey: true
},
path: {
type: sequelize.Sequelize.STRING
},
type: {
type: sequelize.Sequelize.STRING
}
});
Media.sync();
Firstly, Media.belongsTo(User...) will add a field media_id to your Media model, which is not what you want. Try instead:
User.belongsTo(Media, {
as: 'media',
foreignKey: {
name: 'media_id',
allowNull: false
}
});
Then, you should modify your query:
// Find all users with media where media.id === user.media_id
User.findAll({
include: [{
model: Media,
where: { id: Sequelize.col('user.media_id') }
}]
})
I'm trying to implementing this mysql command on sequelize, but as far as i'm newbie to use this library i can't implementing that
i want to make this sql command:
SELECT * FROM users
join users_contacts_lists on users_contacts_lists.mobile_number = users.mobile_number
WHERE users_contacts_lists.user_id = 1
My models to create database schema:
'use strict';
var config = require('../config');
var User = config.sequelize.define('users', {
id: {
type: config.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
password: {
type: config.Sequelize.STRING
},
username: {
type: config.Sequelize.STRING
},
mobileNumber: {
type: config.Sequelize.STRING,
field: 'mobile_number'
},
status: {
type: config.Sequelize.STRING
},
}, {freezeTableName: true});
var UsersContactsLists = config.sequelize.define('users_contacts_lists', {
id: {
type: config.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
userId: {
type: config.Sequelize.INTEGER,
field: 'user_id'
},
mobileNumber: {
type: config.Sequelize.STRING,
field: 'mobile_number', defaultValue: 0
}
}, {freezeTableName: true});
UsersContactsLists.belongsTo(ChannelsTypes, {foreignKey: 'user_id'});
User.hasMany(Channels, {foreignKey: 'id'});
User.sync();
UsersContactsLists.sync();
module.exports =
{
users: User,
usersContactsLists: UsersContactsLists
};
how can i resolve this problem? Thanks in advance
You can define the target key and the foreign key both in a relation like this:
User.belongsTo(UsersContactsLists, {targetKey:'mobileNumber',foreignKey: 'mobileNumber'});
And then you can use this:
User.findAll({
include: [{
model: UsersContactsLists,
where: {
userId: 1
}
}]
})
Fiddled around a bit, does this statement do what you want?
User.findAll({
include: [{
model: UsersContactsLists,
where: {
userId: 1
}
}]
When I try to create a new Conversation item Sequelize will return an object with id: null eventhough there is an valid id in the database. How can I get Sequelize to return the last inserted id to the newly created item?
Conversation.create({
type: 'private',
createdBy: 1,
}).then(conversation => {
reply(conversation);
});
Will return
{
"type": "conversations",
"id": null,
"createdBy": 1,
"created_at": "2016-03-18T01:47:48.000Z"
}
My code:
const Conversation = model.define('Conversation', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
},
type: {
type: Sequelize.ENUM,
values: ['private', 'group'],
validate: {
isIn: ['private', 'group'],
},
},
createdBy: {
type: Sequelize.INTEGER,
field: 'created_by',
},
}, {
tableName: 'conversations',
timestamps: true,
createdAt: 'created_at',
updatedAt: false,
getterMethods: {
type: () => 'conversations',
},
});
const User = model.define('User', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
},
firstName: {
type: Sequelize.STRING,
field: 'first_name',
allowNull: false,
},
lastName: {
type: Sequelize.STRING,
field: 'last_name',
allowNull: true,
},
email: {
type: Sequelize.STRING,
allowNull: false,
},
profileImg: {
type: Sequelize.STRING,
field: 'profile_img',
allowNull: false,
},
password: Sequelize.STRING,
}, {
tableName: 'users',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
getterMethods: {
type: () => 'users',
},
});
Conversation.belongsToMany(User, {
foreignKey: 'conversation_id',
otherKey: 'user_id',
through: 'conversation_user',
timestamps: false,
});
User.belongsToMany(Conversation, {
as: 'conversations',
foreignKey: 'user_id',
otherKey: 'conversation_id',
through: 'conversation_user',
timestamps: false,
});
Yo need to put autoIncrement: true in id field:
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
}
Personally I would advice to skip the id column as sequalize does it automatically for you and works nicely.
hope it helps :)
Problem was my MySQL version (5.6 instead of 5.7), updated it and now I'm getting id's of the created items in the promise.
I'm not sure about how Sequelize is working with id field, I get null if I do instance.id, bug I can get the real value at DB if I do the following:
console.info(instance.id); // null
console.info(instance.get('id')); // 25 => Real ID
console.info(instance.getDataValue('id')); // 25 => Real ID
Something similar is happening with other fields like createdAt and updatedAt.
In order to get the real value at id field and other related fields, I added following logic to Model declaration:
class FooModel extends Model {
// ...
/**
* #inheritdoc
*/
public async save(options?: SaveOptions<TModelAttributes>): Promise<this> {
await super.save(options);
this.loadBaseData();
return this;
}
/**
* #inheritdoc
*/
public async reload(options?: FindOptions<TModelAttributes>): Promise<this> {
await super.reload(options);
this.loadBaseData();
return this;
}
private loadBaseData() {
this.id = this.getDataValue('id');
this.createdAt = this.getDataValue('createdAt');
this.updatedAt = this.getDataValue('updatedAt');
}
}
because if you only build without save it then:
instance.id // null
so you need:
instance.save()
instance.id // someNumber