【问题标题】: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()应该是起点。

任何帮助表示赞赏!

【问题讨论】:

    标签: sql node.js sequelize.js where-clause


    【解决方案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']]
    })
    

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

    【讨论】:

    • 这看起来很有希望,如果有帮助,我会研究一下并检查这个答案。谢谢!
    猜你喜欢
    • 2012-09-28
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 2022-06-10
    • 2022-02-15
    相关资源
    最近更新 更多