是否可以在Sequelize中对多态多对多模型进行Eager加载? 模型数据库查询意外的#1 意外#2 SQL

问题描述

我具有这种结构,旨在通过Sequelize实现多态多对多关联中的渴望加载。

赋予选项 include 时,它返回意外结果(例如不属于此标签的食谱和帖子

模型

// Food model
Food.belongsToMany(models.Tag,{
  through: {
    model: "tag_taggable",unique: false,scope: { taggable_type: "food" }
  },foreignKey: "taggable_id",constraints: false
});
// Recipe model
Recipe.belongsToMany(models.Tag,scope: { taggable_type: "recipe" }
  },constraints: false
});
// Post model
Post.belongsToMany(models.Tag,scope: { taggable_type: "post" }
  },constraints: false
});
// Tag model
Tag.belongsToMany(models.Food,unique: false
    // scope: { taggable_type: "food" }
  },foreignKey: "tag_id",constraints: false
});

Tag.belongsToMany(models.Recipe,unique: false
    // scope: { taggable_type: "recipe" }
  },constraints: false
});

Tag.belongsToMany(models.Post,unique: false
    // scope: { taggable_type: "post" }
  },constraints: false
});

Tag.prototype.getTaggables = async function (options) {
  const recipes = await this.getRecipe(options);
  const foods = await this.getFood(options);
  const posts = await this.getPost(options);
  return posts.concat(recipes).concat(foods);
}
// Tag_Taggable junction model
const TagTaggable = sequelize.define(
  "TagTaggable",{
    id: { type: DataTypes.BIGINT,primaryKey: true,autoIncrement: true },tag_id: { type: DataTypes.BIGINT,unique: "tt_unique_constraint" },taggable_id: { type: DataTypes.BIGINT,unique: "tt_unique_constraint",references: null },taggable_type: { type: DataTypes.STRING,}
);

数据库

标记记录:

+----+--------+-------------+---------------+---------------------------+
| id | tag_id | taggable_id | taggable_type |                           |
+----+--------+-------------+---------------+---------------------------+
| 1  | 1      | 1           | food          | fast,hamburger            |
+----+--------+-------------+---------------+---------------------------+
| 2  | 1      | 1           | recipe        | fast,Caesar Salad Recipe  |
+----+--------+-------------+---------------+---------------------------+
| 3  | 1      | 2           | food          | fast,bacon                |
+----+--------+-------------+---------------+---------------------------+
| 4  | 2      | 1           | post          | fresh,Post 1              |
+----+--------+-------------+---------------+---------------------------+
| 5  | 2      | 2           | recipe        | fresh,french Salad Recipe |
+----+--------+-------------+---------------+---------------------------+
| 6  | 2      | 3           | recipe        | fresh,Greek Salad Recipe  |
+----+--------+-------------+---------------+---------------------------+

查询

查询#1:查找所有标签包括与其相关联的(食物,帖子,食谱),并加载它们

const tags = await Tag.findAll({
  include: [
    { model: db["Food"] /*,required: true*/ },{ model: db["Post"] /*,{ model: db["Recipe"] /*,]
});

return tags[0]; // first tag found

预期:仅出现食物(“汉堡”,“培根”)食谱(“凯撒沙拉食谱”)

{ id:1,name:"fast",foods: [ {hamburger},{bacon} ],recipes: [ {caesar salad recipe} ],posts: [] }

输出

[
    0: { 
        id: 1,name: "fast",foods: [ 
            {
                name: "hamburger",taggable_id: 1,tag_id: 1
            },{
                name: "bacon",taggable_id: 2,tag_id: 1
            } 
        ],recipes: [ 
            {
                name: "Caesar Salad Recipe",{
                name: "french Salad Recipe",posts: [ 
            {
                name: "Post 1",{
                name: "Post 2",tag_id: 1
            } 
        ]
    }
]

意外的#1

显示不应快速出现在标签中的两则帖子和一份食谱

包括相关模型时,范围似乎不影响内部联接(taggable_type看起来像被忽略)。

如果我在tags0上调用getTaggables,我会在数组中获得预期的项目(但是这并不急于加载

tags[0].getTaggables() // => [ {hamburger},{bacon},{caesar salad recipe} ]

查询2(反向):查找与“培根”相关的所有标签

const food = await Food.findOne({
    where: { id: 2 },include: [
        { 
            model: db["Tag"] // required: true
        }
    ]
});

预期

{ id:2,name:"bacon",tags:[ {fast} ] }

输出

{
    id: 2,name: "bacon",tags: [ 
        {
            name: "fast",tag_taggable: {
                taggable_id: 2,tag_id: 1
            }
        },{
            name: null
            tag_taggable: {
                taggable_id: 2,tag_id: 2
            }
        } 
    ]

意外#2

它在Tag include中包含了错误的模型(其在标签中包含 recipe ),显示为null(某种程度上是其配方)

sql

查询#1 正在生成错误SQL查询之一: Tag.include(Food,Recipe,Post)

SELECT 
    `Tag`.`id`,`Tag`.`name`,`Tag`.`color`,`Tag`.`created_at` AS `createdAt`,`Tag`.`updated_at` AS `updatedAt`,`foods`.`id` AS `foods.id`,`foods`.`name` AS `foods.name`,`foods->tag_taggable`.`taggable_id` AS `foods.tag_taggable.taggable_id`,`foods->tag_taggable`.`tag_id` AS `foods.tag_taggable.tag_id`,`recipes`.`name` AS `recipes.name`,`recipes->tag_taggable`.`taggable_id` AS `recipes.tag_taggable.taggable_id`,`recipes->tag_taggable`.`tag_id` AS `recipes.tag_taggable.tag_id` 

FROM
    `tag` AS `Tag` 
    
LEFT OUTER JOIN `tag_taggable` AS `foods->tag_taggable` 
ON `Tag`.`id` = `foods->tag_taggable`.`tag_id` 

LEFT OUTER JOIN `food` AS `foods` 
ON `foods`.`id` = `foods->tag_taggable`.`taggable_id` 

LEFT OUTER JOIN `tag_taggable` AS `recipes->tag_taggable` 
ON `Tag`.`id` = `recipes->tag_taggable`.`tag_id` 

LEFT OUTER JOIN `recipe` AS `recipes` 
ON `recipes`.`id` = `recipes->tag_taggable`.`taggable_id`;

LEFT OUTER JOIN `tag_taggable` AS `post->tag_taggable` 
ON `Tag`.`id` = `posts->tag_taggable`.`tag_id` 

LEFT OUTER JOIN `post` AS `posts` 
ON `posts`.`id` = `posts->tag_taggable`.`taggable_id`;

查询#2 生成的第二个错误SQL查询 Food.include(Tag)

SELECT 
    `Food`.`id`,`Food`.`name`,`tags`.`id` AS `tags.id`,`tags`.`name` AS `tags.name`,`tags->tag_taggable`.`taggable_id` AS `tags.tag_taggable.taggable_id`,`tags->tag_taggable`.`tag_id` AS `tags.tag_taggable.tag_id` 
    
FROM 
    `food` AS `Food` 
    
LEFT OUTER JOIN `tag_taggable` AS `tags->tag_taggable` 
ON `Food`.`id` = `tags->tag_taggable`.`taggable_id` 

LEFT OUTER JOIN `tag` AS `tags` 
ON `tags`.`id` = `tags->tag_taggable`.`tag_id` 
AND `tags->tag_taggable`.`taggable_type` = 'food' WHERE `Food`.`id` = 2;

包裹

"sequelize": "^6.3.4","sequelize-cli": "^6.2.0","sqlite3": "^5.0.0",

我如何处理这个模型,包括急切的装载情况?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)