我正在使用sequelize.js,我有两个表“媒体”和“标签”,其中一个媒体项目可以有多个标签,一个标签可以标记多个媒体项目(
tags.belongsToMany(media)
&media.belongsToMany(tags)
)。
我倾向于通过标签查询媒体项目,所以
media.findAll({ include: { model: 'tags', where: { tagName: 'movie' } } }
问题是这样的(诸如
include: 'tags', where: { '$tags.tagName$': 'movie' }
之类的变体将仅包含与它们返回的所有媒体项的“标签”字段中的tagName匹配的标签。这不是我想要的。我想在上看到所有标签媒体项已返回,但仅具有与其关联的 tagName“电影”标签的媒体项。
sequelize 是否提供任何方法来做到这一点?
快速演示:
media.findOne({ include: { model: 'tags', where: { tagName: 'Pins' } } }
// Returns:
{
mediaId: 3555,
checksum: 'xyz',
fileType: 'image',
extension: 'jpg',
title: null,
description: null,
downloaded: true,
downloadType: null,
dateDownloaded: null,
createdAt: '2023-12-02T19:51:50.000Z',
updatedAt: '2023-12-08T01:46:09.000Z',
tags: [
{
tagId: 26,
tagName: 'Pins',
parentTagId: null,
createdAt: '2023-12-06T23:32:53.000Z',
updatedAt: '2023-12-08T01:30:14.000Z',
mediaTagMapping: {
mappingId: 16919,
mediaId: 3555,
tagId: 26,
createdAt: '2023-12-06T23:32:54.000Z',
updatedAt: '2023-12-08T02:15:02.000Z'
}
},
]
},
// Expected:
{
mediaId: 3555,
checksum: 'xyz',
fileType: 'image',
extension: 'jpg',
title: null,
description: null,
downloaded: true,
downloadType: null,
dateDownloaded: null,
createdAt: '2023-12-02T19:51:50.000Z',
updatedAt: '2023-12-08T01:46:09.000Z',
tags: [
{
tagId: 26,
tagName: 'Pins',
parentTagId: null,
createdAt: '2023-12-06T23:32:53.000Z',
updatedAt: '2023-12-08T01:30:14.000Z',
mediaTagMapping: {
mappingId: 16919,
mediaId: 3555,
tagId: 26,
createdAt: '2023-12-06T23:32:54.000Z',
updatedAt: '2023-12-08T02:15:02.000Z'
}
},
{
tagId: 27,
tagName: 'Beauty',
parentTagId: null,
createdAt: '2023-12-06T22:32:53.000Z',
updatedAt: '2023-12-08T01:30:15.000Z',
mediaTagMapping: {
mappingId: 16919,
mediaId: 3555,
tagId: 26,
createdAt: '2023-12-06T22:32:54.000Z',
updatedAt: '2023-12-08T02:15:04.000Z'
}
},
]
},
*/
注意:这个问题实际上之前就被问过,但那是 5 年前的事了,得到了 0 个回复,所以我不确定旧项目的刷新政策是什么。老问题的链接:在 Sequelize 中,如何按项目的多对多关联值过滤项目,并显示其所有关联值?
我找到了一个(?)解决方案。解决方案是创建一个仅用于过滤的 second 关联,并包含两者:
// First association, this will return the tags as normal
sequelizeDatabase.models.media.belongsToMany(sequelizeDatabase.models.tags, {
through: sequelizeDatabase.models.mediaTagMapping,
uniqueKey: 'mappingId',
foreignKey: 'mediaId',
otherKey: 'tagId',
});
// Second association, this will return only matching tags
sequelizeDatabase.models.media.belongsToMany(sequelizeDatabase.models.tags, {
through: sequelizeDatabase.models.mediaTagMapping,
uniqueKey: 'mappingId',
foreignKey: 'mediaId',
otherKey: 'tagId',
as: 'tagFilter'
});
运行它:
await sequelizeDatabase.models.media.findAll({
include: [ {
model: sequelizeDatabase.models.tags,
}, {
model: sequelizeDatabase.models.tags,
required: true,
as: 'tagFilter',
where: {
tagName: 'Beauty'
}
}
]
});
// Returns
{
mediaId: 3589,
checksum: '20b7c7af0ecdf1f61da2d78277e02ebad747a65428bbfa43ac86cd272c7f1a2a59019c0295f4c114032fdd4b69c8242e05be2ab9a5029e7ccc8b727e7d660e3a',
url: null,
fileType: 'image',
extension: 'jpg',
title: null,
description: null,
downloaded: true,
downloadType: null,
dateDownloaded: null,
createdAt: '2023-12-02T19:51:51.000Z',
updatedAt: '2023-12-08T01:46:09.000Z',
tags: [
{
tagId: 26,
tagName: 'Pins',
createdAt: '2023-12-06T23:32:53.000Z',
updatedAt: '2023-12-08T01:30:14.000Z',
mediaTagMapping: [Object]
},
{
tagId: 32,
tagName: 'Me',
createdAt: '2023-12-06T23:40:45.000Z',
updatedAt: '2023-12-08T01:30:14.000Z',
mediaTagMapping: [Object]
},
{
tagId: 33,
tagName: 'Beauty',
createdAt: '2023-12-06T23:40:47.000Z',
updatedAt: '2023-12-08T01:30:14.000Z',
mediaTagMapping: [Object]
},
{
tagId: 39,
tagName: 'pfp/previous',
createdAt: '2023-12-06T23:42:48.000Z',
updatedAt: '2023-12-08T01:30:14.000Z',
mediaTagMapping: [Object]
}
],
tagFilter: [
{
tagId: 33,
tagName: 'Beauty',
createdAt: '2023-12-06T23:40:47.000Z',
updatedAt: '2023-12-08T01:30:14.000Z',
mediaTagMapping: [Object]
}
]
}
不幸的是,似乎必须在启动时定义关联,因为 Sequelize 似乎不允许您在没有预定义的情况下包含多个关联。
如果我没有收到任何更好的答案,我会在几天左右将此标记为解决方案。