Sequelize high memory usage with n:m assosiations - node.js

my setup is sequelize.js with node.js and express.js. I'm having an model called 'Room'. This model has some n:m associations. Since i filter my data acording to the association data, every time i getting all the Rooms, I have to include all associations.
Room.findAll({
where: whereCondition,
include: ['purposes', 'prices', 'furnishing', 'technic', 'floor']
}).then(data => {
res.send(data);
});
An example how an association is setup:
// room <-> technic m:n
db.room.belongsToMany(db.technic, {
as: "technic",
through: "room_technic",
foreignKey: "roomId",
otherKey: "technicId"
});
db.technic.belongsToMany(db.room, {
as: "rooms",
through: "room_technic",
foreignKey: "technicId",
otherKey: "roomId"
});
This leads to a big query. I found an quite old answer, about memory problems with one big query: https://stackoverflow.com/a/23081751/2834550
The suggestion was to split up the query to have multiple ones.
So, I'm theoratically asking how to split it up?
And is it still the best way to overcome the bad memory performance?
Thanks,
Luc

One way to do it is to use pagination/limiting:
Doc link
A good practice is to have a default pagination on your REST API resources, and an optional query string parameters of LIMIT and SKIP

Related

Does defining relationships in models using sequilizejs partially or completely remove the need for using include parameter?

What is the advantage of defining relationships in sequilizejs on a given modal , is it just for the purpose of more succinct queries ? I do see an example such as (Found HERE) :-
User.hasMany(Picture)
User.belongsTo(Picture, { as: 'ProfilePicture', constraints: false })
user.getPictures() // gets you all pictures
user.getProfilePicture() // gets you only the profile picture
User.findAll({
where: ...,
include: [
{ model: Picture }, // load all pictures
{ model: Picture, as: 'ProfilePicture' }, // load the profile picture. Notice that the spelling must be the exact same as the one in the association
]
})
Does having a relationship defined avaoid the usage of too many queries with the include param ? I.E. does the below :-
user.getPictures() // gets you all pictures
user.getProfilePicture() // gets you only the profile picture
Do away with the more verbose :-
User.findAll({
where: ...,
include: [
{ model: Picture }, // load all pictures
{ model: Picture, as: 'ProfilePicture' }, // load the profile picture. Notice that the spelling must be the exact same as the one in the association
]
})
I am using sequilizejs in an already existing project so the models were not created by me and hence an trying to understand the advantage of having relationships such as belongsTo and hasOne being defined in a model. Would appreciate any insight into the same.
P.S. I do see a more detailed documentation HERE
Also , as a secondary question what are the other advantages of using relationships in a db ?
Defining the relationships is actually required to be able to use include in the queries.
By using include, Sequelize will create a JOIN query, so you can get data from multiple collections which are linked by relationships without the need of a second query.
When using belongsTo, hasOne, hasMany etc. these methods are creating aditional columns in the table to create the relationships between the tables.

Sequelize Getting model object from relations

When I define a relation, I specify what model object it is related to:
models.Guest.belongsTo(models.Member, {foreignKey: 'guestId', as: 'guest'});
Now to use this relationship in a query, I need to specify the model object again:
Guest.findAll({
include: models.Member,
as: 'guest'
});
In my setup, all the relationships are defined in a single file, while individual models are in files by themselves. The setup defines the models object, which has all of them - and the thing is available to application logic.
What I would like is define some of the more complex queries directly in the Guest model object, to abstract them away from the application. To do this, I'd like to find the models.Member object - retrieving it somewhere out of the relationship:
Guest.findMembers = function(){
return this.findAll({
include: <that model that guest is related to>,
as: 'guest'
});
}
Please imagine that the example is complex enough that it warrants solving. Lots more other joins and where statements, for instance. Or data processing after the fact.
I can pass the models object into the setup of each individual object, so its siblings can be accessed. Is that my only option?
You can just also add an include in your include mode also
Guest.findMembers = function(){
return this.findAll({
include: [{
model: <that model that guest is related to>,
as: 'guest',
include: [{
model: <that model that guest is related this included model>,
as: 'setTheAlias',
}]
}]
});
}

Multiple relation n:n to one table in sequelize

I am using Sequelize for PostgresSQL. For example: I've got two tables Friendship and User. To make friendship possible for every user, I've got two relations n:n.
Associations in Sequelize
User.hasMany(Friendship,
{
as: "friendshipsAsked",
foreignKey: "asked_user_id",
joinTableName: "friendship"
});
User.hasMany(Friendship,
{
as: "friendshipsAsking",
foreignKey: "asking_user_id",
joinTableName: "friendship"
});
Friendship.belongsTo(User,
{
...
});
Friendship.belongsTo(User,
{
...
});
My biggest problem is querying friendships for user. When I've got user model, I have to get user.getFriendshipsAsking() and user.getFriendshipsAsked() and then merge both.
Is there any possibility to change relations so I can have user.getFriendships() in SQL such that it will perform like SELECT * FROM frienships WHERE requesting_user_id = 'user.id' OR requested_user_id = 'user.id'?
I would like to have a better solution to model friendship between users in the database?

How to implemet a Many-to-Many relationship in Sequelizejs which also have relationship attributes?

So there are a lot of answers that explain how you model a Many-to-Many relationship in sequelizejs using hasMany() etc. But none of them has explained how and where do you store attributes which are created due to such an association, for eg: A customer can belong to or have many merchants and a merchant can have many customers, one such attribute of this relationship is a unique customer_id for a particular merchant-cutomer. Now where should this key(and any other detail) reside if we follow this: Stackoverflow answer
If you want additional attributes in your join table, you can define a model for the join table in sequelize, before you define the association, and then tell sequelize that it should use that model for joining, instead of creating a new one:
Customer = sequelize.define('customer', {})
Merchant = sequelize.define('merchant', {})
MerchantCustomers = sequelize.define('merchant_customers', {
customer_id: DataTypes.INTEGER
})
Merchant.belongsToMany(Customer, { through: MerchantCustomers })
Customer.belongsToMany(Merchant, { through: MerchantCustomers })
customer.addMerchant(merchant, { customer_id: 42 })
http://docs.sequelizejs.com/en/latest/docs/associations/#belongs-to-many-associations
To access the join table attributes:
c.getMerchants().then(function (merchants) {
merchants[0].merchant_customer.customer_id // Or perhaps merchant_customers, can't remember
});

Join across multiple junction tables with Sequelize

I have a database with three primary tables: users, teams, and folders joined by two junction tables, users_teams and teams_folders. There is a many-to-many relationship between users and teams and between teams and folders (a user can be on more than one team and teams can own more than one folder).
Sequelize does a wonderful job of managing the user-teams and teams-folder relationship, but I can find no way to establish a relationship between users and folders.
Is there any way to join across two junction tables without resorting to raw SQL?
There seems to be no way to accomplish this elegantly or in a reasonable number of steps. I have tried methods like user.getFolders(), Folder.findAll({ include: [User] }), but Sequelize doesn't seem to be able to understand a three level hierarchy.
Assuming the following relations:
User.belongsToMany(Team, { through: 'users_teams'});
Team.belongsToMany(User, { through: 'users_teams'});
Folder.belongsToMany(Team, { through: 'teams_folders'});
Team.belongsToMany(Folder, { through: 'teams_folders'});
You should be able to load everything in one go using nested includes:
User.findAll({
include: [
{
model: Team,
include: [
Folder
]
}
]
});
You seem to be on the right track already with the example you have given in your post :). The only thing you need to change is instead of passing the User model directly in include, you pass an object with a model property and a further nested include property
Pay attention to following:
Define relations in both directions
Check you have foreignKey, otherKey in correct order
User.belongsToMany(Team, {
through: 'users_teams',
foreignKey: 'user_id',
otherKey: 'team_id'
});
Team.belongsToMany(User, {
through: 'users_teams',
foreignKey: 'team_id',
otherKey: 'user_id'
});

Resources