首页 > 解决方案 > 如何按包含的实体搜索/选择,但将所有相关实体包含到结果集中

问题描述

在我的应用程序中,我使用的是 sequelize ORM。有几个实体: ATool可以有TagsCategories

现在我想搜索所有Tool具有特定 s 的 s Tag,但我想包括Tag该工具的所有相关 s(不仅仅是特定的)。如果我现在将一条where语句放入包含中,则只有指定Tag的 s 会包含在结果集中(请参阅 参考资料[2])。我试图限制Tag外部 where 语句中的 s(请参阅 参考资料[1]),但这也无济于事。

例子

工具A有标签t1t2t3。现在我想搜索所有具有 Tag 的工具t3,但结果集应包含所有三个标签。

预期结果:

Tool A
\
 - Tag t1
 - Tag t2
 - Tag t3
db.Tool.scope('published').findAll({
    where: { '$tool.tag.name$': filter.tag }, // [1] Does not work
    include: [
        {
            model: db.User,
            attributes: ['id', 'username']
        },
        {
            model: db.Tag,
            attributes: ['name'],
            through: { attributes: [] },
            // [2] Would limit the result specified tag
            // where: {
            //     name: {
            //         [Op.and]: filter.tag
            //     }
            // }
        },
        {
            model: db.Category,
            attributes: ['id', 'name', 'views'],
            through: { attributes: ['relevance'] },
            where: {
                id: {
                    [Op.and]: filter.category
                }
            }
        }
    ],
    where: {
        title: {
            [Op.like]: `%${filter.term}%`,
        }
    },
    attributes: ['id', 'title', 'description', 'slug', 'docLink', 'vendor', 'vendorLink', 'views', 'status', 'createdAt'],
    order: [['title', 'ASC'], [db.Tag, 'name', 'ASC']]
})

我知道我可以通过首先通过标签执行选择来执行此操作(db.Tag.findAll()而不是db.Tool.findAll()我已经在项目的其他地方完成了此操作),但同时我也希望能够通过另一个实体进行过滤(Category) 一样的方法。所以Tool.findAll()应该是起点。

任何帮助表示赞赏!

标签: sqlnode.jssequelize.jswhere-clause

解决方案


首先,您的顶级查询中有两个 where 子句:

 where: { '$tool.tag.name$': filter.tag }, // [1] Does not work
 // ...
 where: {
        title: {
            [Op.like]: `%${filter.term}%`,
        }
    },

我认为您最好的方法是literal在 WHERE 子句中使用子查询。基本上,我们想要找到所有具有正确标签且包含filter.term.

WHERE 的子查询部分看起来像......

SELECT ToolId FROM ToolTags WHERE TagId='t2';

受到这篇文章Sequelize - where 子句中的子查询的子查询解决方案的启发

// assuming your join table is named 'ToolTags' in the database--we need the real table name not the model name 
const tempSQL = sequelize.dialect.QueryGenerator.selectQuery('ToolTags',{
    attributes: ['ToolId'],
    where: {
          TagId: filter.tag
    }})
    .slice(0,-1); // to remove the ';' from the end of the SQL

db.Tool.scope('published').findAll({
    where: {
        title: {
            [Op.like]: `%${filter.term}%`,
        },
        id: {
            [Op.In]: sequelize.literal(`(${tempSQL})`)
        }
    },
    include: [
        {
            model: db.User,
            attributes: ['id', 'username']
        },
        {
            model: db.Tag,
            attributes: ['name'],
            through: { attributes: [] },
        },
       // {
       //     model: db.Category,
       //     attributes: ['id', 'name', 'views'],
       //     through: { attributes: ['relevance'] },
       //     where: {
       //         id: {
       //             [Op.and]: filter.category
       //         }
       //     }
       // }
    ],
    attributes: ['id', 'title', 'description', 'slug', 'docLink', 'vendor', 'vendorLink', 'views', 'status', 'createdAt'],
    order: [['title', 'ASC'], [db.Tag, 'name', 'ASC']]
})

我现在评论了你的类别加入。我认为您应该在向查询中添加更多内容之前尝试隔离标签的解决方案。


推荐阅读