如何通过关联查询续集模型,但包括所有关联对象?

Posted

技术标签:

【中文标题】如何通过关联查询续集模型,但包括所有关联对象?【英文标题】:How to query sequelize model by association, but include all associated objects? 【发布时间】:2017-12-05 20:23:44 【问题描述】:

尝试通过所有关联的属性进行查询,但获取所有关联

# FAQs:  id: 1, name: 'How to do it?' ,  id: 2, name: 'How to FIX it?' 
# tags:  id: 1, slug: 'api' ,  id: 2, slug: 'beta' 
# taggings:  id: 1, faqId: 1, mainEntityId: 1, mainEntityType: 'faq' ,  id: 2, faqId: 1, mainEntityId: 2, mainEntityType: 'faq' 

const query =  slugs: ['api'] 
const foundFAQs = await this.models.FAQ.findAll(
  where: 
    '$taggings.tag.slug$':  $in: query.slugs ,
  ,
  include: [
    model: this.models.Tagging,
    as: "taggings",           
    include: [
      model: this.models.Tag,         
      as: 'tag',
    ],        
  ],
)

我的模型定义:

models.Tagging.belongsTo(models.Tag,  as: 'tag', onDelete: 'cascade' );
models.Tag.hasMany(models.Tagging,  as: 'taggings', onDelete: 'cascade' );
models.Tag.belongsToMany(models.FAQ,  through: models.Tagging, as: 'faqs' );
models.FAQ.hasMany(models.Tagging,  as: 'taggings', onDelete: 'cascade' );
models.FAQ.belongsToMany(models.Tag,  through: models.Tagging, as: 'tags' );

您预计会发生什么?

我想获取与 TAG api 相关联的所有常见问题解答并拥有其所有标签。

对象: 编号:1, 名称:“怎么做?”, 标签: [ id: 1, slug: 'api' , id: 2, slug: 'beta' ]

实际发生了什么?

查询返回对象: 编号:1, 名称:“怎么做?”, 标签: [ id:1,slug:'api' ]

输出

SELECT \"faq\".\"id\", \"faq\".\"name\", \"faq\".\"bankId\", \"faq\".\"priority\", 
\"faq\".\"publishedLocales\", \"faq\".\"createdAt\", \"faq\".\"updatedAt\", \"taggings\".\"id\" 
AS \"taggings.id\", \"taggings\".\"tagId\" AS \"taggings.tagId\", \"taggings\".\"locked\" 
AS \"taggings.locked\", \"taggings\".\"sdkId\" AS \"taggings.sdkId\", \"taggings\".\"guideId\" 
AS \"taggings.guideId\", \"taggings\".\"newsId\" AS \"taggings.newsId\", \"taggings\".\"faqId\" 
AS \"taggings.faqId\", \"taggings\".\"apiId\" AS \"taggings.apiId\", \"taggings\".\"createdAt\" 
AS \"taggings.createdAt\", \"taggings\".\"updatedAt\" AS \"taggings.updatedAt\", \"taggings->tag\".\"id\" 
AS \"taggings.tag.id\", \"taggings->tag\".\"name\" AS \"taggings.tag.name\", \"taggings->tag\".\"slug\" 
AS \"taggings.tag.slug\", \"taggings->tag\".\"tagType\" AS \"taggings.tag.tagType\", \"taggings->tag\".\"mainEntityId\" 
AS \"taggings.tag.mainEntityId\", \"taggings->tag\".\"createdAt\" 
AS \"taggings.tag.createdAt\", \"taggings->tag\".\"updatedAt\" 
AS \"taggings.tag.updatedAt\" FROM \"faqs\" AS \"faq\" INNER JOIN \"taggings\" 
AS \"taggings\" ON \"faq\".\"id\" = \"taggings\".\"faqId\" LEFT OUTER JOIN \"tags\" 
AS \"taggings->tag\" ON \"taggings\".\"tagId\" = \"taggings->tag\".\"id\" WHERE \"faq\".\"bankId\" = 'bank.csas' 
AND \"taggings->tag\".\"slug\" IN ('faq') ORDER BY \"faq\".\"priority\" DESC;

方言: postgres

方言版本: pg@^6.1.0

数据库版本: PostgreSQL 10.1

续集版本: 4.23.2

用最新版本测试:否 (4.23.2)

节点: 8.6.0

我不确定这是错误还是我做错了什么。

谢谢

【问题讨论】:

你能分享你的模型和关系代码吗?此外,另一种选择可能是从另一个方向接近;找到标签和include 相关的常见问题解答。 @Will 模型定义已添加。是的,这是另一种选择,但我必须得到相当困难的地图结果,当我要寻找两个标签时,这里会有重复,不是吗? 可能。您是否尝试过将 where 子句移动到标签的 include 中? @Will 是的,我有。这是同样的问题。 【参考方案1】:

您希望包含每条记录的所有相关数据,但要根据相关数据过滤这些记录。您需要让 Sequelize 生成类似于以下内容的 SQL:

SELECT "faq"."id", ....
FROM "faqs" AS "faq"
INNER JOIN "taggings" AS "taggings" ON "faq"."id" = "taggings"."faqId"
LEFT OUTER JOIN "tags" AS "taggings->tag" ON "taggings"."tagId" = "taggings->tag"."id"
LEFT OUTER JOIN "tags" AS "taggings->tagdata" ON "taggings"."tagId" = "taggings->tagdata"."id"
WHERE "faq"."bankId" = 'bank.csas' AND "taggings->tag"."slug" IN ('faq')
ORDER BY "faq"."priority" DESC;

这样的事情可能会奏效:

const foundFAQs = await this.models.FAQ.findAll(
  where: 
    '$taggings.tag.slug$':  $in: query.slugs ,
  ,
  include: [
    model: this.models.Tagging,
    as: "taggings",           
    include: [
      model: this.models.Tag,         
      as: 'tag',
    ,
      model: this.models.Tag,         
      as: 'tagdata',
    ],
  ],
)

这里的想法是,您正在执行要过滤的连接,然后执行另一个连接以获取过滤行的额外记录。

【讨论】:

【参考方案2】:

今天这对我有用——嵌套includes

getReferralPlanForThisCode(parent, args, context) 
    let referralCode = args;
    return Promise.resolve()
        .then(() => 
            let referralPlan = connectors.ReferralPlans.findAll(
                include: [
                    model: connectors.ReferralCodes,
                    where: unique_referral_code: referralCode,
                    include: [
                        model: connectors.epUserData, as: 'referrer',
                    ],
                ],
            )
            return referralPlan;
        )
        .then(referralPlan => 
            return referralPlan;
        )
        .catch((err) => 
            console.log(err);
        );

【讨论】:

以上是关于如何通过关联查询续集模型,但包括所有关联对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有额外查询的情况下删除续集中的关联?

续集限制包括关联

通过模型关联对nodejs进行续集

续集:如何为关联做等效的 findAndCountAll

续集关联 On 或 ON

如何获取满足匹配对象的关联文档