Sequelize Many-to-many querying model - javascript

Have some troubles with querying data.
Have 2 models with many to many relationships.
1st - S3FileData, 2nd - Playlists, they are connected through PlaylistContent table.
Also S3FileData is connected with User with User has-many playlists.
I need to query S3Files which belongs to user, but are not presented in user playlist.
I have playlist Id,userId.
Also I need offset and limit methods, so I tried to query this using findAndCountAll
But got no luck with it.
Would be very appreciate for any help :)

You will require include(joins in SQL) that will connect all these tables.
Something like this but first you will need to intertwine your models(db tables) which will look something like this:
User.belongsToMany(Profile, { through: Grant });
Profile.belongsToMany(User, { through: Grant });
User.hasMany(Grant);
Grant.belongsTo(User);
Profile.hasMany(Grant);
Grant.belongsTo(Profile);
Reference:
https://sequelize.org/master/manual/advanced-many-to-many.html
Now, Once you are through the joins you'll require to use those joins using include keyword in your findAll (or findAllAndCount as per the requirement):
Some basic code (You will need to try and tweak accordingly, this is rough code):
S3Files.findAll({
include: [
{
model: user,
attributes: ['some columns']
include: {
model: userPlaylist,
attributes: ['some columns'],
required: false
},
where: {[Op.and]: Sequelize.where(Sequelize.col('userPlaylist.userId'), 'is not' null)},
attributes: ['some columns']
]
});
lastly for offset and limit you'll require basic SQL logic of LIMIT and OFFSET
sample snippet from official docs for offset and limit:
Project
.findAndCountAll({
where: {
title: {
[Op.like]: 'foo%'
}
},
offset: 10,
limit: 2
})
Reference for the same:
https://sequelize.org/v5/manual/models-usage.html

Related

How to make sql sequelize query with nested relations where clause

Im currently working on a budget tracking web app that has the corresponding database setup
enter image description here
So basically i have multiple transactions reladed to a single account, as well as multiple accounts related to a single user
i want to come up with a sequelize query that allows me to view every transaction done by any account corresponding to a single user
Assuming that you have associations look like this:
// these definitions are simplified for demonstration purposes
User.hasMany(Account);
Account.hasMany(Transaction);
Account.belongsTo(User);
Transaction.belongsTo(Account);
We can get all user's transactions like this:
const transactions = await Transaction.findAll({
include: [{
model: Account,
required: true,
include: [{
model: User,
required: true,
where: {
id: userId // here is the condition on a certain user id
}
}]
}]
})

Looking for Active Model Serializer like nested, associative output for Sequelize

Please forgive me if my research was inadequate. I've been reading the docs and searching this site to no avail for over an hour and I could really use some expert help.
With Rails, I can use Active Model Serializer to send data associated with the set queried. For example, let us say that I have Users, and Users have many Posts. Let us say that I want output that looks like this:
[
- {
id: 1,
username: "Matz",
posts: [
- {
id: 35,
title: "Hello world",
content_body: "This is the content of my post."
},
-{
id: 98,
title: "Foo Bar",
content_body: "This is the content of my other post."
}]},
]
Using Active Model Serializer this would be trivial. What I'm hoping is to get similar output using Sequelize.
My associations are working fine, and I am able to do for instance this:
return db.Users.findByPk(user_id)
.then(user => user.getPosts())
.then(posts => res.send(posts))
* edited to add *
One problem is that what I would really like to do is put the include inside of the user.getPosts(), for example.
What I need is the get the Posts belonging to a User, then get the Tag to which those Posts belong.
Thanks so much for any help. I am trying to avoid too many fetch requests.
Include within .getPosts does work. I had not understood the docs entirely.
Because I imported the models as so in my app.js:
const db = require('./models');
I needed to write the following:
return db.Users.findByPk(user_id)
.then(user => user.getPosts({
include: [{
model: db.Tags
}]
}))
.then(posts => res.send(posts))

angular firestore how to retreive many to many relation data

I coming from RDMS background. I having difficulty to get the relation data through associate collection, here is the collection i got...
users collection
- user_1
- name: abc
- email: xxxx#example.com
- user_2
- name: efg
- email: efg#example.com
groups collection
- group_tech
- name: tech
- group_finance
- name: finance
groupUsers collection
- groupUserID
- groupID: group_tech
- userID: user_1
I want list the user in the tech group, basically i can query like this
this.groupUsersCol = this.afs.collection('groupUsers');
this.groupUsersCol.ref.where('groupID', '==', this.params.gid)
.onSnapshot(function(querySnapshot) {
var employees = [];
querySnapshot.forEach(function(doc) {
// here i only get the user id, how i get the user doc?
// Also, i cannot direct call this.afs.doc(...)
console.log("user", doc.data())
});
});
there is another way round to solve my problem which modeling my data in this way.
users collection
- user_1
- name: abc
- email: xxxx#example.com
- groups: {
group_tech: true
}
- user_2
- name: efg
- email: efg#example.com
- groups: []
groups collection
- group_tech
- name: tech
- users: {
user_1: true
}
- group_finance
- name: finance
the good thing about to store your data in this way, is so convenience to retrieve the data. like...
if you want get all user in the group, you can query in
this.afs.collection('users').ref.where('groups.'+group_id, '==', true)
same thing to users, get user's groups, absolutely easy. but there is the downside when remove user from the group. you need remove from 2 table.
Please Advice! It would be good by sharing your experience and practice way to do, welcome and thanks you so much!
I'd recommend the second way, as you mentioned it makes for much better querying and simplifies your security rules. Do note there is a 20k limit on composite-indexes, so don't do it if your users are in thousands of groups.
To solve the downside, instead of handling the "delete" client-side do it server-side with a Cloud Function. Just monitor both users and groups with a Cloud Functions listener, look for changed fields, and if any of the relationships are now false delete both sides of the relationship.

Sequelize where on many-to-many join

I am hoping somebody can help me. I am using the Sequelize ORM for express.js and I have a working many-to-many relationship between 2 tables.
For the sake of simplifying my query lets pretend my tables are Users, Books and UserBooks where UserBooks has UserId, BookId and an additional column (Lets say its NoOfTimesRead).
What I want to do is something like:
user.getBooks({
where: {
"userBooks.NoOfTimesRead": 0
}
});
If I type:
user.getBooks();
This works and returns all books, I just haven't been able to figure out how to query this by the additional column on the joining table.
I hope this makes sense,
Thanks for taking a look!
With Belongs-To-Many you can query based on through relation and
select specific attributes. For example using findAll with through
User.findAll({
include: [{
model: Project,
through: {
attributes: ['createdAt', 'startedAt', 'finishedAt']
where: {completed: true}
}
}]
});
Basically you can use through option and include the relationship that you linked. More can be found here

Sails.js Waterline query by association

I'm developing and app with Sails.js and using Waterline orm for db. I'm developing functionality for users to do friend requests and other similar requests to each other. I have following URequest model for that:
module.exports = {
attributes: {
owner: {
model: 'Person'
},
people: {
collection: 'Person'
},
answers: {
collection: 'URequestAnswer'
},
action: {
type: 'json' //TODO: Consider alternative more schema consistent approach.
}
}
};
Basically owner is association to Person who made the request and people is one-to-many association to all Persons who the request is directed. So far fine.
Now I want to have a controller which returns all requests where certain user is involved in meaning all requests where user is either in owner field or in people. How I do query like "give me all rows where there is association to person P" ? In other words how I ca know which URequest models have association to a certain Person?
I tried something like this:
getRequests: function (req, res) {
var personId = req.param('personId');
URequest.find().where({
or: [
{people: [personId]}, //TODO: This is not correct
{owner: personId}
]
}).populateAll().then(function(results) {
res.json(results);
});
},
So I know how to do the "or" part but how do I check if the personId is in people? I know I should somehow be able to look into join-table but I have no idea how and couldn't find much from Waterline docs relating to my situation. Also, I'm trying to keep this db-agnostic, though atm I'm using MongoDB but might use Postgres later.
I have to be honest this is a tricky one, and, as far as I know what you are trying to do is not possible using Waterline so your options are to write a native query using query( ) if you are using a sql based adapter or native otherwise, or try doing some manual filtering. Manual filtering would depend on how large of a dataset you are dealing with.
My mind immediately goes to reworking your data model a bit, maybe instead of a collection you have a table that stores associations. Something like this:
module.exports = {
attributes: {
owner: {
model: 'URequest'
},
person: {
model: 'Person'
}
}
Using the sailsjs model methods (like beforeCreate) you could auto create these associations as needed.
Good Luck, I hope you get it working!

Categories