Sequelize: get MIN/MAX Dates from association - mysql

I have to tables - one for events and another one for the dates (start-end) this event is "active".
id name
-- ----
1 event 1
2 event 2
And then the EventDates
eventId start end
------- ----- ---
1 2018-01-14 2018-01-15
1 2018-01-17 2018-01-18
2 2018-02-14 2018-02-18
Events and EventDates are setup using hasMany()
Event.DATES = Event.hasMany(models.EventDates, {
as: 'dates',
foreignKey: 'eventId',
});
Querying for all Events including the EventDates like this:
await Event.findAll({
include: [{ association: Event.DATES }]
});
returns a nested Event list with all the EventDates - great.
[
{
id: 1,
name: 'event 1',
dates: [
{
start: '2018-01-14',
end: '2018-01-15',
},
{
start: '2018-01-17',
end: '2018-01-18',
},
],
},
{
id: 2,
name: 'event 2',
dates: [
{
start: '2018-02-14',
end: '2018-02-18',
},
],
}
]
But now I want to add a maxEndDate to an Event so I can check if it still active or if all EventDates are in the past. I can do that manually adding another LEFT JOIN like this:
# ...
LEFT OUTER JOIN (SELECT eventId, MAX(end)
FROM `EventDates`
GROUP BY eventId) dates
ON `Event`.`id` = `dates`.`eventId`
# ...
But how could I achieve the same thing with Sequelize?
[
{
id: 1,
name: 'event 1',
maxEndDate: ??,
dates: [
{
start: '2018-01-14',
end: '2018-01-15',
},
{
start: '2018-01-17',
end: '2018-01-18',
},
],
},
{
id: 2,
name: 'event 2',
maxEndDate: ??,
dates: [
{
start: '2018-02-14',
end: '2018-02-18',
},
],
}
]

It very tricky to get result with group by and has many association , but at last I found the way and here it is :
Event.findAll({
raw : true,
attributes : [ 'Event.*' , 'EventDates.eventId' , [sequelize.fn('max', sequelize.col('EventDates.end')),'end']],
include : {
model : EventDates ,
attributes :[]
},
group : ['Event.id','EventDates.eventId']
})
I think you can achieve your last out put that by this , I haven't tried this but this is the way you can go ahead
Event.findAll({
raw : true,
attributes : [ 'Event.*' , 'dates.*' , 'EventDates.eventId' , [sequelize.fn('max', sequelize.col('EventDates.end')),'end']],
include : [
{
model : EventDates ,
attributes :[]
},
{
model : EventDates ,
as : 'dates',
required : false,
separate : true
}
]
group : ['Event.id','EventDates.eventId']
})

Related

Sequlize bulkCreate with updateOnDuplicates return all values(duplicated and not duplicated)

I have this code
const users = await User.bulkCreate(newUsers, {
updateOnDuplicate: ['name'],
});
Its query return all values in response like
[
{
id:1,
name: 'Andrew'
},
{
id:2,
name: 'John'
},
{
id:3,
name: 'Andrew'
},
]
But in database that query writes only unique value. Only 1 Andrew and 1 John.
I need to return only 2 records not 3

trying to group by artist using Sequelize and NodeJs

I have a simple Mysql table like the following fields:
Id, songName, ArtistName, siglosID
example data:
1 My Way Frank Sinatra 1
2 Big Balls ACDC 2
3 New York Frank Sinatra 3
4 Highway To Hell ACDC 4
I want to return an object to return to graphql where data is grouped by artistName
something like the following:
[ artistName: 'ACDC':[
{ id: 2, songName: 'Big Balls', artistName: 'ACDC', siglosId: '2' },
{ id: 4, songName: 'Highway To Hell', artistName: 'ACDC', siglosId: '4' },],
[ artistName: 'Frank Sinatra':[
{ id: 3, songName: 'New York', artistName: 'Frank Sinatra', siglosId: '3' },
{ id: 1, songName: 'My Way', artistName: 'Frank Sinatra', siglosId: '1' },],
]
What I actually get back:
[
{ id: 2, songName: 'Big Balls', artistName: 'ACDC', siglosId: '2' },
{
id: 1,
songName: 'My Way',
artistName: 'Frank Sinatra',
siglosId: '1'
}
Not sure how to use group properly or do I need to use a join?
My code:
getAllSongs: {
type: new GraphQLList(SongType),
async resolve() {
const mytest = await dbSong.findAll({
order: ["artistName"],
group: ["artistName"],
raw: true,
});
console.log("test Songs grouped by artist: ", mytest);
// return dbSong.findAll({ raw: true });
return dbSong.findAll({
order: ["artistName"],
group: ["artistName"],
raw: true,
});
},
},
},
});`

mongodb aggregate $nin condition with another collection

SELECT * FROM collection1 c1 WHERE c1.mobileNum NOT IN(SELECT mobileNumer FROM collection2) ORDER by c1.createdAt DESC
collection 1 :
=============
[{
name: 'abc',
mobileNum: 1234,
createdAt: DateTime
},{
name: 'efg',
mobileNum: 5678,
createdAt: DateTime
},
{
name: 'ijk',
mobileNum: 222222,
createdAt: DateTime
},
{
name: 'mno',
mobileNum: 33333,
createdAt: DateTime
}
]
collection 2 :
=============
[{
age: 24,
mobileNumer : 1234,
createdAt: DateTime
},{
age: 25,
mobileNumer : 0000,
createdAt: DateTime
},
{
age: 25,
mobileNumer : 1111,
createdAt: DateTime
}]
first have the mysql query.
second i have the mongodb collections are collection1 and collection 2.
need to convert the mysql statement into equivalent mongodb aggregate query.
can someone help?
$lookup - Join collection 1 (mobileNum) with collection 2 (mobileNumer).
$match - Filter document with matchedDocs is empty array ($size: 0).
$sort - Sort by createdAt descending.
$unset - Remove matchedDocs field.
db.col1.aggregate([
{
"$lookup": {
"from": "col2",
"localField": "mobileNum",
"foreignField": "mobileNumer",
"as": "matchedDocs"
}
},
{
$match: {
"matchedDocs": {
$size: 0
}
}
},
{
$sort: {
createdAt: -1
}
},
{
"$unset": "matchedDocs"
}
])
Sample Mongo Playground

Find rows where association count is between passed values

I am trying to find all the rows with their count of associated model.
It should only return those rows which have count of associations between two passed values.
This is what I tried, but getting sql exception.
db.Employee.findAll({
where: {
$assignedJobCount$: {
[Op.between]: [0, 100],
},
},
include: [
{
model: db.AssignedJob,
required: true,
attributes: ['emp_id'],
},
],
attributes: [
'id',
'alternate_mobile',
['employee_unique_id', 'unique_id'],
[Sequelize.fn('COUNT', Sequelize.col('AssignedJobs.emp_id')), 'assignedJobCount'],
],
order: [['id', 'ASC']],
subQuery: false,
group: ['Employee.id'],
limit: 20,
});
return JSON.parse(JSON.stringify(mechanics));
};
It throws below error,
sql:
'SELECT
`Employee`.`id`,
`Employee`.`alternate_mobile`,
`Employee`.`employee_unique_id` AS `unique_id`,
COUNT(`AssignedJobs`.`emp_id`) AS `assignedJobCount`,
`AssignedJobs`.`id` AS `AssignedJobs.id`,
`AssignedJobs`.`emp_id` AS `AssignedJobs.emp_id`
FROM
`employee` AS `Employee`
INNER JOIN `assigned_jobs` AS `AssignedJobs` ON
`Employee`.`id` = `AssignedJobs`.`emp_id`
WHERE
`assignedJobCount` BETWEEN 0 AND 100
GROUP BY
`Employee`.`id`
ORDER BY
`Employee`.`id` ASC
LIMIT 20;',
parameters: undefined
}
SequelizeDatabaseError: Unknown column 'assignedJobCount' in 'where clause'
I fixed it by converting where clause into having clause as below.
db.Employee.findAll({
having: {
assignedJobCount: {
[Op.between]: [0, 100],
},
},
include: [
{
model: db.AssignedJob,
required: true,
attributes: ['emp_id'],
},
],
attributes: [
'id',
'alternate_mobile',
['employee_unique_id', 'unique_id'],
[Sequelize.fn('COUNT', Sequelize.col('AssignedJobs.emp_id')), 'assignedJobCount'],
],
order: [['id', 'ASC']],
subQuery: false,
group: ['Employee.id'],
limit: 20,
});
return JSON.parse(JSON.stringify(mechanics));
};

Change Alias of Distinct for sequelize

I am using below query on my code that is
await to( mymodel.aggregate('cid', 'DISTINCT', {plain: false,where:{created_by:user.id}}));
and query out put on console is
SELECT DISTINCT(`cid`) AS `DISTINCT` FROM `mymodel` AS `mymodel` WHERE `mymodel`.`created_by` = 7;
I got below output that is
ids --------------- [ { DISTINCT: 9 }, { DISTINCT: 10 }, { DISTINCT: 11 } ]
I want to change the alias that is DISTINCT to id. How i do that like below
ids --------------- [ { id: 9 }, { id: 10 }, { id: 11 } ]
I don't think .aggregate() supports aliasing fields however it's simple to turn this into a regular query instead.
await mymodel.findAll({
attributes: [ [ Sequelize.fn('DISTINCT', 'cid'), 'id' ] ],
where: { created_by: user.id }
});
Here we're utilising Sequelize.fn() to create the DISTINCT on cid and using the array attribute notation to alias it to id. More info on this here.