如何按包含的实体搜索/选择,但将所有相关实体包含到结果集中

Posted

技术标签:

【中文标题】如何按包含的实体搜索/选择,但将所有相关实体包含到结果集中【英文标题】:How to search for/select by included entity but include all related entities into result set 【发布时间】:2020-11-10 07:34:42 【问题描述】:

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

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

示例

工具A 具有标签t1t2t3。现在我想搜索所有具有标签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();I've already done this elsewhere in my project),但同时我也希望能够通过另一个过滤实体 (Category) 以同样的方式。所以Tool.findAll()应该是起点。

任何帮助表示赞赏!

【问题讨论】:

【参考方案1】:

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

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

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

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

SELECT ToolId FROM ToolTags WHERE TagId='t2';

受这篇文章Sequelize - subquery in where clause的子查询解决方案的启发

// 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']]
)

我暂时注释掉了您的类别加入。我认为您应该在向查询中添加更多内容之前尝试隔离标签的解决方案。

【讨论】:

这看起来很有希望,如果有帮助,我会研究一下并检查这个答案。谢谢!

以上是关于如何按包含的实体搜索/选择,但将所有相关实体包含到结果集中的主要内容,如果未能解决你的问题,请参考以下文章

按两个实体搜索不适用于 JpaRepository

如何按不相关的实体过滤核心数据

实体框架:如何从相关实体中选择特定列

如何在包含相关实体的实体中应用过滤条件

实体框架选择仅包含一个孩子的人

如何使用实体框架的导航属性来构建视图模型