Sequelize findAll() try to get unregistered field - node.js

i have problem with sequelize, i try to use findAll() to get data from my table, but there is an error which says unknown column jobs.userId in field list which i never register in my model or in my table
i have tried to use findAndCountAll() but still have same error, i also tried to remove all associatoin at get same result, the only work solution so far is put userId on exclude array
here's my controller
const jobData = await jobs.findAll({
attributes:{exclude:['updatedAt']},
include:[{
model:jobOwners,
as:'owner',
attributes:['id','profilePicture'],
include:[{
model:users,
as:'user',
attributes:['id','name'],
},{
model:districts,
as:'district',
attributes:['id','name']
}]
}]
});
here's my jobs model
'use strict';
module.exports = (sequelize, DataTypes) => {
const jobs = sequelize.define('jobs', {
jobOwnerId:{
type:DataTypes.INTEGER,
allowNull:false
},
caption: {
type:DataTypes.STRING,
allowNull:false
},
description: {
type:DataTypes.TEXT,
allowNull:false
},
districtId: {
type:DataTypes.INTEGER,
allowNull:false
},
address: {
type:DataTypes.TEXT,
allowNull:false
},
poster: {
type:DataTypes.TEXT,
allowNull:true
},
contactPerson: {
type:DataTypes.STRING,
allowNull:false
}
}, {});
jobs.associate = function(models) {
jobs.belongsTo(models.jobOwners,{as:'owner',foreignKey:'jobOwnerId'})
jobs.belongsTo(models.districts,{as:'districts', foreignKey:'districtId'})
};
return jobs;
};
here's my table
CREATE TABLE jobs (
id int(11) NOT NULL,
jobOwnerId int(11) NOT NULL,
caption varchar(255) NOT NULL,
description text,
districtId int(11) NOT NULL,
address text NOT NULL,
poster text,
contactPerson varchar(15) NOT NULL,
createdAt datetime NOT NULL,
updatedAt datetime NOT NULL
)
here's is the query result shown on console
SELECT jobs.id, jobs.jobOwnerId, jobs.caption, jobs.description, jobs.districtId, jobs.address,
jobs.poster, jobs.contactPerson, jobs.createdAt, jobs.userId, owner.id AS owner.id, owner.profilePicture AS owner.profilePicture,
owner->user.id AS owner.user.id, owner->user.name AS owner.user.name, owner->district.id
AS owner.district.id, owner->district.name AS owner.district.name FROM jobs AS jobs
LEFT OUTER JOIN jobOwners AS owner ON jobs.jobOwnerId = owner.id LEFT OUTER JOIN users AS owner->user
ON owner.userId = owner->user.id LEFT OUTER JOIN districts AS owner->district ON owner.districtId = owner->district.id;
there should be no jobs.userId

Problem solved, the problem not from jobs model or jobs controller, but it comes from users model, i create association hasMany jobs and it couses the problem..

Related

How Can I write INNER Join query using Sequelize on Node.js

I have two tables. One is tblEmailAuditLog having columns Id, OrderId, Body, CommunicationType, CreatedOn, Reciever, WorkflowStatusId, IsSuccess another one is tblLookUp having column names as LU_LookUpValue and LU_LOOKUPID. I want to join the two tables based on the columns (CommunicationType and LU_LOOKUPID)
My inner join query looks as below:
select Id, OrderId, Body, CommunicationType, CreatedOn, Reciever, WorkflowStatusId, IsSuccess, LU_LookUpValue from tblEmailAuditLog INNER JOIN tblLookUp on tblEmailAuditLog.CommunicationType = tblLookUp.LU_LOOKUPID;
I am trying to write the above query using sequelize ORM.
I have tried the below things.
1.
let auditLogs = await MediMarket.TblEmailAuditLog.findAll({
include: [
{
model: MediMarket.TblLookUp,
required: true,
where: { orderId: req.body.orderId },
},
],
});
2.
let auditLogs = MediMarket.TblEmailAuditLog.hasMany(
MediMarket.TblLookUp,
{ foreignKey: "CommunicationType" }
);
MediMarket.TblLookUp.belongsTo(MediMarket.TblEmailAuditLog, {
foreignKey: "LU_LOOKUPID",
});
MediMarket.TblEmailAuditLog.findAll({
where: { orderId: req.body.orderId },
include: [MediMarket.TblLookUp],
});
But it is not giving the expected result.

Sequelize Update with Object

I have a code using sequelize to update one record and then return this updated record:
const companyId = req.params.id
const companyNewDetail = req.body
console.log("companyNewDetail", companyNewDetail)
await Company.update(companyNewDetail, {
where: {
companyId,
},
})
const company = await Company.findOne({
where: {
companyId,
},
})
res.status(200).send({ status: 0, data: company })
It is working but I have to seperate into two query statements. Is there a way I can mix them together? I want to pass the update parameter with a object rather than destructuring the object and assign to the instance one by one.
The returning option of Model.update still only supports PostgreSQL for sequelize v6.
For example:
import { sequelize } from '../../db';
import { Model, DataTypes, Sequelize } from 'sequelize';
// const sequelize = new Sequelize('sqlite::memory:');
class Company extends Model {}
Company.init(
{
companyId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
name: DataTypes.STRING,
},
{ sequelize, tableName: 'companies' },
);
(async function test() {
try {
await sequelize.sync({ force: true });
// seed
await Company.create({ name: 'google' });
// test
const companyId = 1;
const companyNewDetail = { name: 'reddit' };
const result = await Company.update(companyNewDetail, {
where: {
companyId,
},
returning: true,
});
console.log(result);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
If you use postgres dialect, you will get the following result:
Executing (default): DROP TABLE IF EXISTS "companies" CASCADE;
Executing (default): DROP TABLE IF EXISTS "companies" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "companies" ("companyId" SERIAL , "name" VARCHAR(255), PRIMARY KEY ("companyId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'companies' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "companies" ("companyId","name") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): UPDATE "companies" SET "name"=$1 WHERE "companyId" = $2 RETURNING *
[
1,
[
Company {
dataValues: [Object],
_previousDataValues: [Object],
_changed: {},
_modelOptions: [Object],
_options: [Object],
isNewRecord: false
}
]
]
The first element of the result array is the number of affected rows for the updating operation. The second element is the sequelize model instances of updated rows.
For sqlite3, you will get:
Executing (default): DROP TABLE IF EXISTS `companies`;
Executing (default): DROP TABLE IF EXISTS `companies`;
Executing (default): CREATE TABLE IF NOT EXISTS `companies` (`companyId` INTEGER PRIMARY KEY AUTOINCREMENT, `name` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);
Executing (default): PRAGMA INDEX_LIST(`companies`)
Executing (default): INSERT INTO `companies` (`companyId`,`name`,`createdAt`,`updatedAt`) VALUES (NULL,$1,$2,$3);
Executing (default): UPDATE `companies` SET `name`=$1,`updatedAt`=$2 WHERE `companyId` = $3
[ undefined, 1 ]
So, you need to do an additional query for other databases after updating the rows in the table.

Sequelize node js create record with autoincrement field validation error

I have sequelize model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Image = sequelize.define('Image', {
id: {
type: DataTypes.BIGINT,
autoIncrement: true,
unique: true,
primaryKey: true
},
url: {
type: DataTypes.STRING,
allowNull: false,
}
},
{
timestamps: false
});
Image.associate = (models) => {
//some association here
};
return Image;
};
I am trying to create a new record like that:
const img = await Images.create({
url: '/newUrl'
}).catch(error => {
throw errors.initError(error);
});
it executes a query
Executing (default): INSERT INTO "Images" ("id","url") VALUES
(DEFAULT,'/newUrl') RETURNING *;
and I receive an error
{
"message": "id must be unique",
"type": "unique violation",
"path": "id",
"value": "18",
"origin": "DB",
"instance": {
"id": null,
"url": "/newUrl"
},
"validatorKey": "not_unique",
"validatorName": null,
"validatorArgs": []
}
Should not sequelize handle autoincrement field by itself?
This happens when you have manually created entries into the database providing the id.
To demonstrate this, you can try these into postgres
create table users (id serial NOT NULL PRIMARY KEY, name varchar(40));
insert into users (name) values ('abhinavd');
select * from users;
insert into users (id, name) values (2, 'abhinavd');
insert into users (name) values ('abhinavd');
The last insert will fail complaining that id must be unique
This happens when you have inserted a record and have provided the id manually. next_val('test_id_seq') is only called when the system needs a value for this column and you have not provided one. What you need to do is to update this next_val value.
To fix this you can execute the following in your table
SELECT setval('YourTable_id_seq', (SELECT MAX(id) from "YourTable"));
The name of the sequence is always autogenerated and it follows the following format tablename_columnname_seq.
Just to add to Rodolofo's answer, Postgres users should replace 'YourTable_id_seq' with '"YourTable_id_seq"'. Table name is case-sensitive.
Refer this answer

Access inner join data from sequelize using include

I am trying to join two tables using Sequelize's include as such:
models.user.findAll({include: {model: models.boardMember, required:true}})
.then(function(board) {
console.log(board);
res.render('contact', { title: 'Kontakt', board: board });
});
My models look like this using the sequelize express example:
User (it doesn't quite feel right having the hasMany here instead of in boardMembers, but I didn't want to have the foreign key field in the users table)
module.exports = function(sequelize, DataTypes) {
var user = sequelize.define('user', {
//lots of normal user fields(username, password, access...
}, {
classMethods: {
associate: function(models) {
user.hasMany(models.boardMember, {
foreignKey: {
allowNull: false
}
});
}
}
});
return user;
};
boardMember
module.exports = function(sequelize, DataTypes) {
var boardMember = sequelize.define('boardMember', {
post: {
type: DataTypes.STRING,
unique: false,
allowNull: false
}
});
return boardMember;
};
I then want to access the data returned in a table using handlebars:
{{#each board}}
<tr>
<td>{{boardMembers.post}}</td>
<td>{{firstName}} {{surName}}</td>
<td>{{email}}</td>
</tr>
{{/each}}
Here is where I get it wrong(I think). The names and email appear, but not the post. I've tried using only post as well but to no avail. This is odd I think because the query that is generated looks like this (I removed the createdAt and updatedAt columns to make it shorter for you to read):
SELECT
`user`.`id`, `user`.`username`, `user`.`password`,
`user`.`firstName`, `user`.`surName`, `user`.`email`, `user`.`access`,
`boardMembers`.`id` AS `boardMembers.id`, `boardMembers`.`post` AS `boardMembers.post`,
`boardMembers`.`userId` AS `boardMembers.userId`
FROM
`users` AS `user`
INNER JOIN
`boardMembers` AS `boardMembers` ON `user`.`id` = `boardMembers`.`userId`;
The console.log outputs something like this(the data obviously changed):
[ Instance {
dataValues:
{ id: 2,
username: 'username',
password: 'hashedPassword',
firstName: 'User',
surName: 'Name',
email: 'user#name.com',
access: '0',
boardMembers: [Object] },
...
]
Any help is much appreciated!
Thanks,
Freece
Per the sequelize documentation the value for the include attribute is a list.
You can try with the special value include: [{ all: true, nested: true }] and see if it works for you.
Additionally you have a problem with your template becuase you have stablished a one to many relation and therefore the boardMemebers attribute of model instances are arrays.

Create Association in Sequelize to do a Left Join

I want to do a left join using Sequelize that does the same as this SQL code.
SELECT * FROM events LEFT JOIN zones ON event_tz=zid WHERE event_creator_fk=116;
I have two tables: events and zones (with a list of time zones).
When querying for all the events that are created by a specific user, I also want to get the name of the time zone and other details about the TZ.
I have tried many combinations of solutions by reviewing sample code, other Stack Overflow questions and the documentation as best I can. The query always works, but doesn't do any joins. That is, it below code always returns the list of events, but no time zone data from the zones table. The generated SQL is correct, except it doesn't have the ...LEFT JOIN zones ON event_tz=zid... part.
The below code is wrong. See answers for details.
db.Event.findAll(
{ where: { event_creator_fk: someUserID } },
{ include: [{ model: db.Zone } ]}
);
If I understand correctly, adding associations between tables in sequelize results in an additional column from automatically being created. This is not what I want to do. I do not want Sequelize to modify the tables or database in any way. I want to setup my database and it's tables without Sequelize. Therefore, I am not calling sequelize.sync(). I don't know if there is away to setup associations the way I want.
Model Definitions
module.exports = function (sequelize, DataTypes) {
var Event = sequelize.define('Event', {
eid: {
type: DataTypes.INTEGER,
primaryKey: true
},
event_tz: {
type: DataTypes.INTEGER,
primaryKey: true,
references: "Zone",
referencesKey: "zid"
},
}, {
classMethods: {
associate: function (models) {
return models.Event.hasOne(models.Zone);
}
},
freezeTableName: true,
timestamps: false,
tableName: 'events'
}
);
return Event;
};
module.exports = function (sequelize, DataTypes) {
return sequelize.define('Zone', {
zid: {
type: DataTypes.INTEGER,
primaryKey: true
}
}, {
classMethods: {
associate: function (models) {
return models.Zone.belongsTo(models.Event);
}
},
freezeTableName: true,
timestamps: false,
tableName: 'zones'
});
};
Table Definitions
DROP TABLE IF EXISTS zones;
CREATE TABLE IF NOT EXISTS zones (
zid integer NOT NULL,
country_code character(2) NOT NULL,
zone_name text NOT NULL,
PRIMARY KEY (zid)
);
DROP TABLE IF EXISTS events;
CREATE TABLE IF NOT EXISTS events (
eid BIGSERIAL NOT NULL,
event_tz SERIAL NOT NULL,
PRIMARY KEY (eid),
FOREIGN KEY (event_tz)
REFERENCES zones(zid) MATCH FULL ON DELETE RESTRICT
);
You need to reverse the associations and tell sequelize about your foreign key. belongsTo means 'add the fk to this model':
models.Event.belongsTo(models.Zone, { foreignKey: 'event_tz');
models.Zone.hasOne(models.Event, { foreignKey: 'event_tz');
// or hasMany if this is 1:m
Part of the problem was that I was using the findAll method incorrectly. The query options where and include should have been included as part of the same object. The first parameter to findAll is an options parameter. See here for more details. The correct code should look like the following.
db.Event.findAll(
{
where: { event_creator_fk: someUserID },
include: [{ model: db.Zone } ]
},
);

Resources