Sequelize order with condition - node.js

I am trying to add order in the query but to be based on condition.
The goal is to order users that are in a relation but based on a flag they have
Include in the main query has properties like this
include: { model: User, include: { model: User, as: 'parent' } }
Now on the client, I have 2 columns in the table that have the same property name, but one has property parent and the other does not.
example:
order: [[ { model: User }, 'name', sorting ]]
When I do ordering like above I am sorting with name property but including both User and User as a parent. Is there a way that I can separate these two?
I saw in the docs that sorting is possible with using sequelize.fn but can't find any examples with it. Can anyone help?

To order the parent association which is it a User as well you can do the following
[[‘name’, sorting], [{model: User, as: 'Parent'}, 'name', sorting]]
That should work and hope will help you !

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 Select models referenced in parent/child tables

If I have the following tables
Post - id, title, content, categoryId
Category - id, name
And some categories don't have posts linked to them, how can I select only the categories that are referenced from the Posts table
I found this in their github issues, but its code from V1, which no longer works, however it demonstrates, I think, what I would like to accomplish
ModelA.findAll({
include: [ModelB],
having: 'count(ModelB.id) > 0'
});
If ModelB is referenced one or more times in ModelA, include it.
Edit: I don't really want to include it, as I only need the data from the Category table, and not the Posts table.
I'm using postgres, if it matters.
required tag helps you in this.
ModelA.findAll({
include: [{
model: ModelB,
required: true
]
});
This will only return rows in ModelA which have at least one corresponding entry in ModelB

Sequelize : Get Subquery/Raw Query as model for include

I have gone through the Sequelize doc, but can't find anything helpful
What I want to do is to add raw query or custom model in include, is it possible ?
model.Post.findAll({
include: [{
model: model.User,
attributes: ['fullname', 'profilepic'],
},
{
model: model.PostComments,
},
{
model: "Raw Query"
}
]
}
What I want to achieve is like :
Select post_id, count(*) as total_likes from post_likes group by post_id
I can't achieve this by using simply include, so what I want to do is create a table/model from above query and then use it inside include.
If I use group by withing include it gives group by from top level, and I want to apply group by just for the post_like table.
Please let me know, if it found confusing or not clear.
I was looking to do the same, use a raw query dynamically formed inside the include but there's no possible way to use include without a model https://sequelize.org/master/class/lib/model.js~Model.html#static-method-findAll .
For the purposes of my MySQL I turned my inner join (include) into a where in. I was doing the inner join to avoid the exception This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery . I get this exception because I have a subquery with LIMIT applied.
If it helps anyone:
let rows = await j_model.findAll({
attributes: [...j_columns, `${association}.meta_key_id`],
include: [
{
model: um_model,
as: association,
attributes: ['um_id'],
on: {'j_id' : {$col: 'j.j_id'} }
],
where: {'j_id': {$in: sequelize.literal(`(SELECT * FROM (${massive_inner_raw_query}) as tmp)`)}},
logging: console.log
});
The actual magic is in this line:
where: {'j_id': {$in: sequelize.literal(`(SELECT * FROM (${massive_inner_raw_query}) as tmp)`)}}
The SELECT * FROM removes that exception and lets me do a where in instead of the wanted INNER JOIN. Maybe you can apply a similar deal to your problem.
You can use
Model.findAll({
attributes: [[models.sequelize.literal('CASE WHEN "field1" = true THEN 55
ELSE 23 END'), 'field3']]
}
OR
Model.findAll({
attributes: { include: [[models.sequelize.literal('CASE WHEN "field1" = true THEN 55 ELSE 23 END'), 'field3']]}
}

Mongoose: How to find documents by sub-collection's document property value

I’m using Mongoose version 4.6.8 and MongoLab (MLab). I have a Mongoose schema called “Group” that has a collection of User subdocuments called “teachers”:
var GroupSchema = new Schema({
//…more properties here…//
teachers: [{
type: Schema.ObjectId,
ref: 'User'
}]
});
This is a document from the “groups” collection on MongoLab:
{
//…more properties here…//
"teachers": [
{
"$oid": "5799a9c759feea9c208c004c"
}
]
}
And this is a document from the “users” collection on MongoLab:
{
//…more properties here…//
"username": "bob"
}
But if I want to get a list of Groups that have a particular teacher (User) with the username of “bob”, this doesn’t work (the list of groups is empty):
Group.find({"teachers.username": "bob"}).exec(callback);
This also returns no items:
Group.find().where('teachers.username').equals('bob').exec(callback);
How can I achieve this?
Without some more knowledge of your set up (specifically whether you want anybody named Bob or a specific Bob whose id you could pick up first) - this might be some help although I think it would require you to flatten your teachers array to just their ID's, not single-key objects.
User.findById(<Id of Bob>, function(err, user){
Group.find({}, function(err, groups){
var t = groups.map(function(g){
if(g['teachers'].indexOf(user.id))
return g
})
// Do something with t
})
})
You can use populate to do that.
Try this:
Group.find({})
.populate({
path : 'teachers' ,
match : { username : "bob" }
})
.exec(callback);
populate will populate based on the teachers field (given path) and match will return only those who have username bob.
For more information on mongoose populate options, Please read Mongoose populate documentation.
I think the solution in this case is to get a teacher’s groups through the User module instead of my first inclination which was to go through the Groups module. This makes sense because it is in line with how modern APIs represent a one-to-many relationship.
As an example, in Behance’s API, an endpoint for a user’s projects is:
GET /v2/users/user/projects
And a request to this endpoint (where the User’s username is “matiascorea”) would look like this:
https://api.behance.net/v2/users/matiascorea/projects?client_id=1234567890
So in my case, instead of finding the groups by teacher, I would need to simply find the User (teacher) by username, populate the teacher’s groups, and use them:
User.findOne({username: 'bob'})
.populate('groups')
.exec(callback);
And the API call for this would be:
GET /api/users/user/groups
And a request to this endpoint would look like this:
https://example.com/api/users/bob/groups

How to do find() / where() in associated models

I'm playing with model associations in sails and I'm curious if it's possible to make a query base on the associated field.
Example:
User.js
attributes:{
classes: { collection: 'Class', via: 'students' }
}
Class.js
attributes: {
type: ...
students: { collection: 'User', via: 'classes'}
}
Is there a way to retrieve specific Classes of a Student base on the type of class because right now everything is being returned when I use .populate(). (maybe similar with the logic below)
User
.findOne({name: 'StudentA'})
.populate('classes')
.where({'classes.type':['type1', 'type2']})
.then(....)
Thanks
You can add a where clause to your populate like so:
User
.findOne({name: 'StudentA'})
.populate('classes', {where: {type: ['type1', 'type2']}})
.exec(...)
In addition to where, you can also use skip, limit and sort in the second argument to populate.
Keep in mind this is still (as of this posting) in beta, so if you find any issues where it seems to not be working correctly, please post them to the Waterline GitHub issues forum.

Resources