find using model association - sql

Dialect: postgres
Database version: #latest
Sequelize version: #latest
I'm trying to find out how to use an associate model. I've got 3 models: post, postCity and region. They have the following relation:
postCity (post_id, region_id) associate to post (post_id) and region (region_id). I am using a search function like this:
include: [
{
model: models.postCity,
include:[{model:models.region}],
attributes: [[models.sequelize.fn('count', 'post_id'), 'count']],
}
],
where: {
$or: [
{
"create_by" : {$not: 67}
},
{
// "postCities.region_name":{$iLike: "%Guangazhou2%"}
},
{
"description":{$iLike: "%India%"}
}
]
}
which leads to:
SELECT "post"."post_id", "post"."description", "post"."create_by",
"post"."create_time", "post"."update_time", "post"."country_id",
"postCities"."post_id" AS "postCities.post_id",
"postCities"."region_id" AS "postCities.region_id",
"postCities"."order_no" AS "postCities.order_no",
"postCities.region"."region_id" AS "postCities.region.region_id",
"postCities.region"."region_name" AS "postCities.region.region_name",
"postCities.region"."country_id" AS "postCities.region.country_id",
"postCities.region"."province_id" AS "postCities.region.province_id"
FROM "t_post" AS "post"
LEFT OUTER JOIN "t_post_city" AS "postCities"
ON "post"."post_id" = "postCities"."post_id"
LEFT OUTER JOIN "t_region" AS "postCities.region"
ON "postCities"."region_id" = "postCities.region"."region_id"
WHERE ("post"."create_by" != 67 OR "post"."description" ILIKE '%India%');
When I uncomment "postCities.region_name":{$iLike: "%Guangazhou2%"} then I get this error
column post.postCities.region_name does not exist
I simply like to my query to be like this
... WHERE ("post"."create_by" != 67
OR "post"."description" ILIKE '%India%'
OR "postCities.region_name" ILIKE: "%Guangazhou2%")
Update
I also tried to include [{model:models.region, where:{"region_name":{$iLike: "%Guangazhou2%"}}}] but this doesn't give me the appropriate result.

In order to add condition to included tables, you should wrap condition with $ symbol, like it:
include: [{
model: models.postCity,
include:[{model:models.region}],
attributes: [[models.sequelize.fn('count', 'post_id'), 'count']],
}],
where: {
$or: [{
"create_by" : {$not: 67}
}, {
"$postCities.region.region_name$":{$iLike: "%Guangazhou2%"}
}, {
"description":{$iLike: "%India%"}
}]
}

Related

GROQ: Query one-to-many relationship with parameter as query input

I have a blog built in NextJS, backed by Sanity. I want to start tagging posts with tags/categories.
Each post may have many categories.
Category is a reference on post:
defineField({
name: 'category',
title: 'Category',
type: 'array',
of: [
{
type: 'reference',
to: [
{
type: 'category',
},
],
},
],
}),
This is my GROQ query:
*[_type == "post" && count((category[]->slug.current)[# in ['dogs']]) > 0] {
_id,
title,
date,
excerpt,
coverImage,
"slug": slug.current,
"author": author->{name, picture},
"categories": category[]-> {name, slug}
}
The above works, when it is hardcoded, but swapping out 'dogs' with $slug for example will cause the query to fail. (Where $slug is a param provided)
*[_type == "post" && count((category[]->slug.current)[# in [$slug]]) > 0]
{
$slug: 'travel'
}
How do I make the above dynamic?
Returns all documents that are storefronts // within 10 miles of the user-provided currentLocation parameter ; // For a given $currentLocation geopoint
I can't believe it. Rookie mistake. I needed to pay more attention in the Sanity IDE. (To be fair there was a UI bug that hid the actual issue)
The param should not contain the $. E.g the following works in the GROQ IDE.
{
slug: 'travel'
}

TypeORM activeRecord style query for "where (a & b) or (c & d)"?

I want to use TypeORM to run a query like
... WHERE (a=1 && b=true) OR (a=2 && b=false)
I see a bunch of references to doing this in the QueryBuilder style, but I need to know how to do this using the ActiveRecord style.
You can do this by providing an array of objects to the where: property:
Item.find({
where: [
{ user: { id: userId }, confirmed: "true" },
{ user: { id: userId }, status: "active" }
]
});
The query above would find items that belong to a user where
user matches user id AND is confirmed, or...
user matches user id AND is active
I do not know about TypeORM, however I found this on ruby on rail active query methods:
https://guides.rubyonrails.org/active_record_querying.html#conditions
raw code: ...where("orders_count = ? AND locked = ?", params[:orders], false)
Example Code: ...where(["(a= ? and b= ?) Or (a=? and b=?)", 1, true, 2, false])

Sequelize nested include with required: true generates invalid join

I apologise for the lengthy post in advance!
I am trying to use sequelize in nodeJs to query a Wordpress mysql database with a required: true in a nested include.
However, the generated query includes a bad join (I'd expect the join to be nested like the nested where clause). I don't seem to be able to figure out if I've configured my schema incorrectly or whether I am just doing something else silly.
Any help would be greatly appreciated!
In essence, my schema is:
const Post = sequelize.define('wp_posts', {
ID: {
type: DataType.BIGINT,
primaryKey: true
}
});
const TermRelationship = sequelize.define('wp_term_relationships', {
object_id: {
type: DataType.BIGINT,
primaryKey: true,
allowNull: false
},
term_taxonomy_id: {
type: DataType.BIGINT,
primaryKey: true,
allowNull: false
}
});
const TermTaxonomy = sequelize.define('wp_term_taxonomy', {
term_taxonomy_id: {
type: DataType.BIGINT,
primaryKey: true
}
});
const Term = sequelize.define('wp_terms', {
term_id: {
type: DataType.BIGINT,
primaryKey: true
}
});
The relationships I have defined are:
Post.belongsToMany(TermTaxonomy, {
through: TermRelationship,
otherKey: 'term_taxonomy_id',
foreignKey: 'object_id',
as: 'termTaxonomies'
});
TermTaxonomy.belongsTo(Term, {
foreignKey: 'term_id',
as: 'term'
});
The query I am executing is
const query = {
limit: 1,
include: [
{
model: TermTaxonomy,
required: true,
as: 'termTaxonomies',
include: [
{
model: Term,
as: 'term',
required: true,
}
]
}
]
};
However, the generated query includes a bad join. Here is the generated query. I have included comments where I see the errors:
SELECT
`wp_posts`.*,
`termTaxonomies`.`term_taxonomy_id` AS `termTaxonomies.term_taxonomy_id`,
`termTaxonomies`.`term_id` AS `termTaxonomies.term_id`,
`termTaxonomies`.`taxonomy` AS `termTaxonomies.taxonomy`,
`termTaxonomies`.`description` AS `termTaxonomies.description`,
`termTaxonomies`.`parent` AS `termTaxonomies.parent`,
`termTaxonomies`.`count` AS `termTaxonomies.count`,
`termTaxonomies->wp_term_relationships`.`object_id` AS `termTaxonomies.wp_term_relationships.object_id`,
`termTaxonomies->wp_term_relationships`.`term_taxonomy_id` AS `termTaxonomies.wp_term_relationships.term_taxonomy_id`,
`termTaxonomies->wp_term_relationships`.`term_order` AS `termTaxonomies.wp_term_relationships.term_order`
FROM
(
SELECT
`wp_posts`.`ID`,
`wp_posts`.`post_author`,
`wp_posts`.`post_date_gmt`,
`wp_posts`.`post_content`,
`wp_posts`.`post_title`,
`wp_posts`.`post_excerpt`,
`wp_posts`.`post_status`,
`wp_posts`.`comment_status`,
`wp_posts`.`ping_status`,
`wp_posts`.`post_password`,
`wp_posts`.`post_name`,
`wp_posts`.`to_ping`,
`wp_posts`.`pinged`,
`wp_posts`.`post_modified_gmt`,
`wp_posts`.`post_content_filtered`,
`wp_posts`.`post_parent`,
`wp_posts`.`guid`,
`wp_posts`.`menu_order`,
`wp_posts`.`post_type`,
`wp_posts`.`post_mime_type`,
`wp_posts`.`comment_count`,
-- ERROR
-- wp_terms cannot be joined to wp_posts
`termTaxonomies->term`.`term_id` AS `termTaxonomies.term.term_id`,
`termTaxonomies->term`.`name` AS `termTaxonomies.term.name`,
`termTaxonomies->term`.`slug` AS `termTaxonomies.term.slug`,
`termTaxonomies->term`.`term_group` AS `termTaxonomies.term.term_group`
FROM
`wp_posts` AS `wp_posts`
-- ERROR: bad join!
-- wp_terms cannot be joined to wp_posts
INNER JOIN `wp_terms` AS `termTaxonomies->term` ON `termTaxonomies`.`term_id` = `termTaxonomies->term`.`term_id`
WHERE
(
SELECT
`wp_term_relationships`.`object_id`
FROM
`wp_term_relationships` AS `wp_term_relationships`
INNER JOIN `wp_term_taxonomy` AS `wp_term_taxonomy` ON `wp_term_relationships`.`term_taxonomy_id` = `wp_term_taxonomy`.`term_taxonomy_id`
INNER JOIN `wp_terms` AS `wp_term_taxonomy->term` ON `wp_term_taxonomy`.`term_id` = `wp_term_taxonomy->term`.`term_id`
WHERE
(
`wp_posts`.`ID` = `wp_term_relationships`.`object_id`
)
LIMIT
1
) IS NOT NULL
LIMIT
1
) AS `wp_posts`
INNER JOIN (
`wp_term_relationships` AS `termTaxonomies->wp_term_relationships`
INNER JOIN `wp_term_taxonomy` AS `termTaxonomies` ON `termTaxonomies`.`term_taxonomy_id` = `termTaxonomies->wp_term_relationships`.`term_taxonomy_id`
) ON `wp_posts`.`ID` = `termTaxonomies->wp_term_relationships`.`object_id`;
The error I get is 'Unknown column 'termTaxonomies.term_id' in 'on clause' due to the incorrect join.
The generated query is valid if I either remove required: true or the limit option since it no longer does the strange inner join. However, I just can't seem to get this to work with a required nested include.
FYI: I am using sequelize 4.37.10 with 1.5.3 mysql2 1.5.3.
Thank you very much!
When eager loading, we can force the query to return only those records which have an associated model, effectively converting the query from the default OUTER JOIN to an INNER JOIN. Just remove required:true it will work fine generally this happens when we eager load, probably in your case we are eagerloading.
I hope you find this explanation beneficial.

Is this SQL possible in Sequelize?

I've just started with sequelize and am trying to reproduce the below query.
I have the following Model structure: Review, Entity, ReviewThank
Each Entity can have many Reviews, and each Review can have many ReviewThanks.
An attribute of each review is a 'thumbUp' (boolean) rating.
I'm trying to generate the below query to get a 'thankCount' for each review, along with the Entity rating - thumbUpCount and totalCount - for each Review:
SELECT * FROM (
SELECT COUNT("Review"."id") AS "totalCount", "Review"."EntityId", COUNT(CASE WHEN "Review"."thumbUp" THEN 1 END) AS "thumbUpCount"
FROM "Reviews" AS "Review" GROUP BY "Review"."EntityId"
) AS "EntityRatingTable" LEFT JOIN (
SELECT "Review"."id", "Review"."EntityId", "Review"."uid", "Review"."thumbUp", "Review"."caption", COUNT("ReviewThanks"."id") AS "thankCount"
FROM "Reviews" AS "Review" LEFT OUTER JOIN "ReviewThanks" AS "ReviewThanks" ON "Review"."id" = "ReviewThanks"."ReviewId"
WHERE "Review"."UserId" IN (1) GROUP BY "Review"."id"
) AS "ReviewsTable" ON "ReviewsTable"."EntityId" = "EntityRatingTable"."EntityId";
Is it possible to produce this in sequelize? I've got the "ReviewsTable" query working ok, but unsure how (or if possible) I can join this with the "EntityRatingTable"?
This is what I've got so far:
models.Review.findAll({
attributes: {
include: [
[models.sequelize.fn('COUNT', models.sequelize.col('ReviewThanks.id')), 'thankCount'],
[models.sequelize.fn('COUNT', models.sequelize.col('Review.id')), 'reviewCount'],
],
exclude: ["EntityId", "UserId"],
},
include: [
{
model: models.ReviewThank,
attributes: [],
}, {
model: models.Entity,
}
],
group: ['"Review"."id"', '"Entity.id"'],
})

Sequelize js get count of associated model

Say for example I have a discussions table and replies table.
How do I get the count of replies for each discussion record ?
Models.course_discussions.count({
where: { 'course_id': 105 },
include: [
{model: Models.course_discussions_replies, as: 'replies'}
]
})
.then(function (discussions) {
if (!discussions) {
reply(Hapi.error.notFound());
} else {
console.log("91283901230912830812 " , discussions);
}
});
The above code is converted into the following query -
SELECT COUNT(`course_discussions`.`id`) as `count` FROM `course_discussions` LEFT OUTER JOIN `course_discussions_replies` AS `replies` ON `course_discussions`.`id` = `replies`.`discussion_id` WHERE `course_discussions`.`course_id`=105;
The above code gets me count of discussions. But how do I get the count of the replies for each discussion ?
The following sql query works, but how do I write it in the sequelize way ?
SELECT COUNT( `replies`.`discussion_id` ) AS `count`
FROM `course_discussions`
LEFT OUTER JOIN `course_discussions_replies` AS `replies` ON `course_discussions`.`id` = `replies`.`discussion_id`
WHERE `course_discussions`.`course_id` =105
If you need the discussions and the replies count maybe .replies.length should work for you.
Models.course_discussions.findAll(
where: { 'course_id': 105 },
include: [
{model: Models.course_discussions_replies, as: 'replies'}
]
})
.then(function (discussions) {
// each discussion in discussions will have a
// replies array
discussions[0].repies.length // replies for current discussion
});