How To Group For Multiple Fields In Sequelize - javascript

I need one help related to the sequelize and I am using postgres.
I want to group records in sequelize. Also the form and user value comes after populate or using include method of sequelize.
I have applied this code but it didn't work:-
{
group: ['formId', 'userId', 'responseFrom'],
include: [ { model: forms, as: 'form' }, { model: users, as: 'user' } ]
}
Here the name of table is formAnswers.
[{
"id": 21,
"formId": 1,
"userId": 123,
"formQuestionId": 2,
"answer": "8,5,6",
"responseFrom": "WAITING",
"createdAt": "2020-01-14T02:31:19.173Z",
"form": {
"id": 1,
"name": "Choose Group",
},
"user": {
"id": 123,
"fullName": "Test User",
"username": "test123",
}
},
{
"id": 22,
"formId": 1,
"userId": 123,
"formQuestionId": 1,
"answer": "3",
"responseFrom": "WAITING",
"createdAt": "2020-01-14T02:31:19.178Z",
"form": {
"id": 1,
"name": "Choose Group",
},
"user": {
"id": 123,
"fullName": "Test User",
"username": "test123",
}
}]
This is the sample record, there will be multiple records for each user.
I want to group the records by using formId and userId. Also you can consider responseFrom in group by. I have tried with group in sequelize but its not working.
I need only single record which have formId and userId same. If we are using the above data so the expected output will be:-
[{
"id": 22,
"formId": 1,
"userId": 123,
"formQuestionId": 1,
"responseFrom": "WAITING",
"createdAt": "2020-01-14T02:31:19.178Z",
"form": {
"id": 1,
"name": "Choose Group",
},
"user": {
"id": 123,
"fullName": "Test User",
"username": "test123",
}
}]
I need to apply pagination for this as well so please keep it in mind.

Possible solution: (not tested)
formAnswers.findAll({
attributes: [
sequelize.literal(`DISTINCT ON("form_question_responses"."formId","form_question_responses"."userId","form_question_responses"."responseFrom") 1`),
'id',
'formId',
'userId',
'responseFrom',
],
include: [
{ model: forms, as: 'form', attributes: ['id', 'name'] },
{ model: users, as: 'user', attributes: ['id', 'fullName', 'username'] }
],
// automatically order by as used DISTINCT ON - DISTINCT ON strictly orders based on columns provided
// order: [
// ['formId', 'ASC'],
// ['userId', 'ASC'],
// ],
offset: undefined, // for no offset
limit: 50,
})

Related

Seqelize: Retrieve latest of hasMany relationship

Here is my relationship:
KbDevice.hasMany(KbDeviceEvent, { foreignKey: 'kb_device_id', as: 'events' })
Here is my query:
const allKbDevice = await KbDevice.findAll({
attributes: ['id', 'make', 'model'],
include: [
{
model: KbDeviceEvent,
as: 'events',
attributes: ['id', 'event', 'chamber_id','created_at'],
},
],
});
The issue is, instead of an array, I would like to get one KbDeviceEvent as the latest item based on created_at. I tried to use an include but it kept throwing an error. Can anyone help please?
Do you need to see the actual models to answer this question? If so, please comment.
Thank you,
EDIT:
Here is the result of the above query:
{
"id": "d75f9f96-a468-4c95-8098-a92411f8e73c",
"make": "Toyota",
"model": "Lexus",
"events": [
{
"id": "a737bf7b-2b2e-4817-b351-69db330cb5c7",
"event": "deposit",
"chamber_id": 2,
"created_at": "2022-09-01T22:36:19.849Z"
},
]
}
And I'm looking for:
{
"id": "d75f9f96-a468-4c95-8098-a92411f8e73c",
"make": "Toyota",
"model": "Lexus",
"event": { // I am the latest event
"id": "a737bf7b-2b2e-4817-b351-69db330cb5c7",
"event": "deposit",
"chamber_id": 2,
"created_at": "2022-09-01T22:36:19.849Z"
}
}
Query to fetch the associated model sorted by created_at:
const allKbDevice = await KbDevice.findAll({
attributes: ['id', 'make', 'model'],
include: [
{
model: KbDeviceEvent,
as: 'events',
attributes: ['id', 'event', 'chamber_id','created_at'],
},
],
order: [
[{ model: KbDeviceEvent, as: 'events' }, 'created_at', 'DESC']
],
limit: 1
});
Please note that this will always return the results in this manner:
{
"id": "d75f9f96-a468-4c95-8098-a92411f8e73c",
"make": "Toyota",
"model": "Lexus",
"events": [
{
"id": "a737bf7b-2b2e-4817-b351-69db330cb5c7",
"event": "deposit",
"chamber_id": 2,
"created_at": "2022-09-01T22:36:19.849Z"
},
]
}
since KbDevice model has hasMany relation with KbDeviceEvent model. You can do allKbDevice['events'][0] in your code to get the single event. If you are open to modifying the query, then you can achieve an output which doesn't have any array. However, device would be embedded inside event object. The query would be:
const kbDeviceEvent = await KbDeviceEvent.findAll({
attributes: ['id', 'event', 'chamber_id','created_at'],
order: [
['created_at', 'DESC']
],
limit: 1,
include: [
{
model: KbDevice,
as: 'device',
attributes: ['id', 'make', 'model']
},
]
});
This will output something like this:
{
"id": "a737bf7b-2b2e-4817-b351-69db330cb5c7",
"event": "deposit",
"chamber_id": 2,
"created_at": "2022-09-01T22:36:19.849Z"
"device": {
"id": "d75f9f96-a468-4c95-8098-a92411f8e73c",
"make": "Toyota",
"model": "Lexus",
}
}

Sequelize: When querying data I want to accumulate a specific field in a nested array of objects on the top level of the returned instance

Sequelize 6.0:
I am using findOne on my User model and including Roles and Permissions (they're nested).
The resulting user instance looks (something) like this:
{
"id": "ID",
"username": "user1",
"email": "user#user.com",
"firstName": "User",
"lastName": "Last",
"role": "USER",
"spotifyId": "fakespotifyid10",
"createdAt": "2020-05-19T17:56:26.992Z",
"updatedAt": "2020-05-19T17:56:26.992Z",
"Role": {
"name": "USER",
"Permissions": [
{
"name": "createUser"
},
{
"name": "getUser"
},
{
"name": "updateUser"
}
]
}
}
While this is fine, it would be nice if I could accumulate all the permission names in a top level field named permissions. I believe there's a way to do this but I'm having trouble.
What I'd like the returned user instance to look like:
{
"id": "ID",
"username": "user1",
"email": "user#user.com",
"firstName": "User",
"lastName": "Last",
"role": "USER",
"spotifyId": "fakespotifyid10",
"createdAt": "2020-05-19T17:56:26.992Z",
"updatedAt": "2020-05-19T17:56:26.992Z",
"permissions": ['getUser', 'updateUser', 'createUser']
}
Here is the query for reference:
const findUserByEmailWithPermissions = email =>
User.findOne({
where: {
email,
},
include: [
{
model: Role,
attributes: ['name'],
include: [
{
model: Permission,
attributes: ['name'],
through: {
attributes: [],
},
},
],
},
],
})
Edit:
Here are the relevant associations:
User.belongsTo(Role, { foreignKey: { name: 'role', allowNull: false } })
Role.belongsToMany(Permission, {
through: RolePermission,
foreignKey: { name: 'roleName', allowNull: false },
})

Finding all entries of an associated table in Sequelize Js

I am trying to find an array of entries from an associated table while querying from a main table.
Currently I am getting only one entry under the associated table when i try to query.
For example, I am getting an output as follows.
{
"id": 37,
"name": "Mr Tom",
"books": {
"id": 1278,
"name": "Book 1",
}
}
As you can see the books part comes as an object in an array. I am expecting it to be an array of books.
The following is the code I am using to query the data.
const authorId = req.params.id;
const AuthorDetails = await AUTHOR.findOne({
attributes: [
'id',
'name',
],
where: {
id: authorId,
},
include: [
{
model: BOOKS,
attributes: ['id','name'],
},
],
raw: true,
nest: true,
});
The relationship between the author and books is one to many. Where a
book can have only one author but an author can have many books.
This is defined as follows.
AUTHORS.hasMany(BOOKS);
BOOKS.belongsTo(AUTHORS);
edit: I noticed that when i remove the condition id:authorId it duplicates the author object and gives a unique book . For example
[
{
"id": 37,
"name": "Mr Tom",
"books": {
"id": 1278,
"name": "Book 1",
}
},
{
"id": 37,
"name": "Mr Tom",
"books": {
"id": 1279,
"name": "Book 2",
}
}
]

Return array of data instead of Dictionary - Sequelize

I need post data like array, but I send it always like this:
{
"books": [
{
"id": 19,
"name": "Král Lávra",
"author": "Karel Havlíček Borovský",
"yearOfRelease": "1920",
"price": "120",
"SubjectId": 1,
"UserId": 2,
"SchoolId": 1
},
]
}
I want show result like this:
[
{
"id": 19,
"name": "Král Lávra",
"author": "Karel Havlíček Borovský",
"yearOfRelease": "1920",
"price": "120",
"SubjectId": 1,
"UserId": 2,
"SchoolId": 1
},
]
I use sequelize to connection between database MySQL. This is my code for findAll books:
let books = await ctx.db.Book.findAll({
where: {
UserId: id
},
})
Then I only post to
ctx.body= {
books
}
Thanks for your response.

sequelize include returns only one result

I have a Users table and a Groups table, when I retrieve a single user, I want to get a list of all the groups that user belongs to. I created a joins table named GroupUsers and it has userId and groupId on it, this is how I know that a user belongs to a group. Now, when I try to get the list of groups a user belongs to using the sequelize include on find, it only returns the first match, if the user belongs to various groups. How do I solve this?
Users controller
return models.Users
.find({
include: [{
model: models.Groups,
as: 'groups',
limit: null,
required: false
}],
where: { username }
})
Returns this:
{
"id": 1,
"username": "John",
"phone": "xxxxxxxx",
"email": "john#email.com",
"createdAt": "2017-07-16T20:14:04.744Z",
"updatedAt": "2017-07-16T20:14:04.744Z",
"groups": [
{
"id": 1,
"name": "Test Group",
"type": "Public",
"createdAt": "2017-07-16T20:13:18.392Z",
"updatedAt": "2017-07-16T20:13:18.392Z",
"GroupUsers": {
"userId": 1,
"groupId": 1,
"last_seen": null,
"createdAt": "2017-07-16T20:14:27.903Z",
"updatedAt": "2017-07-16T20:14:27.903Z"
}
}
]
}
Instead of this:
{
"id": 1,
"username": "John",
"phone": "xxxxxxxx",
"email": "john#email.com",
"createdAt": "2017-07-16T20:14:04.744Z",
"updatedAt": "2017-07-16T20:14:04.744Z",
"groups": [
{
"id": 1,
"name": "Test Group",
"type": "Public",
"createdAt": "2017-07-16T20:13:18.392Z",
"updatedAt": "2017-07-16T20:13:18.392Z",
"GroupUsers": {
"userId": 1,
"groupId": 1,
"last_seen": null,
"createdAt": "2017-07-16T20:14:27.903Z",
"updatedAt": "2017-07-16T20:14:27.903Z"
}
},
{
"id": 2,
"name": "Test Group 2",
"type": "Public",
"createdAt": "2017-07-16T20:13:18.392Z",
"updatedAt": "2017-07-16T20:13:18.392Z",
"GroupUsers": {
"userId": 1,
"groupId": 2,
"last_seen": null,
"createdAt": "2017-07-16T20:14:27.903Z",
"updatedAt": "2017-07-16T20:14:27.903Z"
}
}
]
}
I'm sure I'm doing something wrong somewhere I just don't know where, that same thing may also be the cause of sequelize including the joins table in the result: GroupUsers
It appears that in my associations, I did:
Users.belongsToMany(models.Groups, {
through: 'GroupUsers',
as: 'groups',
foreignKey: 'groupId'
});
Instead of :
Users.belongsToMany(models.Groups, {
through: 'GroupUsers',
as: 'groups',
foreignKey: 'userId'
});
Note the foreignKey attribute
And as for the GroupUsers object that is also returned, I removed that by doing:
include: [{
model: models.Groups,
as: 'groups',
attributes: ['id', 'name'],
through: { attributes: [] }
}]
Note the through key which has attributes set to an empty array.

Categories

Resources