Sequelize belongsToMany 关联不通过表工作

Posted

技术标签:

【中文标题】Sequelize belongsToMany 关联不通过表工作【英文标题】:Sequelize belongToMany association not working through table 【发布时间】:2015-04-21 19:45:51 【问题描述】:

我在 PostgreSQL 上使用 Sequelize 来存储属于组织的用户。组织拥有用户可以访问的设备。因此,从本质上讲,用户还通过他们的组织拥有设备。

我设置每个设备都使用组织 ID 与组织相关联,并且每个用户都使用组织 ID 与组织相关联。我正在尝试使用 Sequelize 进行设置以正确阅读它。我正在尽我最大的努力不求助于编写自定义查询,但如果我最终不得不这样做也没关系。

我正在尝试获取与用户 ID 关联的所有设备。当我尝试运行 findAll(...) 命令时,Sequelize 会打印出这个带有错误的疯狂查询。它输出这个查询,然后是一个空集:

SELECT 
    "receiver"."receiver_id" AS "id", 
    "receiver"."organization_id" AS "organizationID", 
    "receiver"."identifier", 
    "receiver"."secret", 
    "receiver"."iterations", 
    "receiver"."sodium", 
    "receiver"."algorithm", 
    "receiver"."created", 
    "receiver"."modified", 
    "receiver"."deleted", 
    "receiver"."organization_id", 
    "users"."user_id" AS "users.id", 
    "users"."password" AS "users.password", 
    "users"."sodium" AS "users.sodium", 
    "users"."email" AS "users.email", 
    "users"."organization_id" AS "users.organizationID", 
    "users"."iterations" AS "users.iterations", 
    "users"."algorithm" AS "users.algorithm", 
    "users"."created" AS "users.created", 
    "users"."modified" AS "users.modified", 
    "users"."deleted" AS "users.deleted", 
    "users"."organization_id" AS "users.organization_id", 
    "users.organizations"."created" AS "users.organizations.created", 
    "users.organizations"."modified" AS "users.organizations.modified", 
    "users.organizations"."organization_id" AS "users.organizations.organization_id" 
FROM "receivers" AS "receiver" 
INNER JOIN (
    "organizations" AS "users.organizations" 
    INNER JOIN "users" AS "users" 
    ON "users"."user_id" = "users.organizations"."organization_id") 
ON "receiver"."receiver_id" = "users.organizations"."organization_id" 
AND ("users"."deleted" IS NULL AND "users"."user_id" = 2) 
WHERE "receiver"."deleted" IS NULL;

我怎样才能更好地编写定义或代码?

非常感谢。

我在 Sequelize 中的表定义:

var organization = sequelize.define( 'organization', 
    'id': 
        type: Sequelize.BIGINT,
        field: 'organization_id',
        allowNull: false,
        primaryKey: true,
        autoIncrement: true
    ,
    'name' : 
        type:  Sequelize.STRING( 256 ),
        field: 'name',
        allowNull: false,
        validate: 
            notEmpty: true
        
    
, 
    'createdAt' : 'created',
    'updatedAt' : 'modified',
    'deletedAt' : 'deleted',
    'tableName' : 'organizations',
    'paranoid'  : true
 );

var user = sequelize.define( 'user', 
    'id': 
        type: Sequelize.BIGINT,
        field: 'user_id',
        allowNull: false,
        primaryKey: true,
        autoIncrement: true
    ,
    'password': 
        type: Sequelize.STRING( 64 ),
        field: 'password',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'sodium': 
        type: Sequelize.STRING( 64 ),
        field: 'sodium',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'email' : 
        type:  Sequelize.STRING( 64 ),
        field: 'email',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'organizationID' : 
        type:  Sequelize.BIGINT,
        field: 'organization_id',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'iterations' : 
        type:  Sequelize.INTEGER,
        field: 'iterations',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'algorithm' : 
        type:  Sequelize.STRING( 8 ),
        field: 'algorithm',
        allowNull: false,
        defaultValue: 'sha256'
    
, 
    'createdAt' : 'created',
    'updatedAt' : 'modified',
    'deletedAt' : 'deleted',
    'tableName' : 'users',
    'paranoid'  : true
 );

var receiver = sequelize.define( 'receiver', 
    'id': 
        type: Sequelize.BIGINT,
        field: 'receiver_id',
        allowNull: false,
        primaryKey: true,
        autoIncrement: true
    ,
    'organizationID': 
        type: Sequelize.BIGINT,
        field: 'organization_id',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'identifier': 
        type: Sequelize.STRING( 64 ),
        field: 'identifier',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'secret' : 
        type:  Sequelize.STRING( 64 ),
        field: 'secret',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'iterations' : 
        type:  Sequelize.INTEGER,
        field: 'iterations',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'sodium': 
        type: Sequelize.STRING( 64 ),
        field: 'sodium',
        allowNull: false,
        validate: 
            notEmpty: true
        
    ,
    'algorithm' : 
        type:  Sequelize.STRING( 8 ),
        field: 'algorithm',
        allowNull: false,
        defaultValue: 'sha256'
    
, 
    'createdAt' : 'created',
    'updatedAt' : 'modified',
    'deletedAt' : 'deleted',
    'tableName' : 'receivers',
    'paranoid'  : true
 );

// Organizations have users and users have organizations
organization.hasMany( user,  'foreignKey' : 'organization_id'  );
user.belongsTo( organization,  'foreignKey' : 'organization_id'  );

// Organizations have receivers
organization.hasMany( receiver,  'foreignKey' : 'organization_id'  );
receiver.belongsTo( organization,  'foreignKey' : 'organization_id'  );

// Receivers to users
user.belongsToMany( receiver,  'through' : 'organizations', 'foreignKey' : 'organization_id'  );
receiver.belongsToMany( user,  'through' : 'organizations', 'foreignKey' : 'organization_id'  );

我用来查询的代码:

// Get the devices for this person
db.receiver.findAll( 
    'include' : [
                
                    'model' : db.user,
                    'where' :  'id' : 2 
                
            ]
 )
.complete( function( error, result ) 
    if( error ) 
        console.log( error );
    
    else 
        console.log( result );
    
 );

【问题讨论】:

为什么在你的 userdevice 表中你有 userID 和 origanizationID? 感谢您撰写该评论。这让我意识到我在那里有额外的代码和一些问题。这是与此问题无关的单独表格的一部分。我希望我写的更清楚! 【参考方案1】:

尝试以下操作,它会选择与 where 语句匹配的用户,并包括与其关联的组织,而组织又包括与其关联的设备,因此您最终应该得到与用户关联的设备。

// Organizations have users
user.belongsTo(organization);
// Organizations have receivers
receiver.belongsTo(organization);


// Get the devices for this person
db.user.find( 
    'include' : [
        model: db.organization,
         include: [model: db.receiver]
        
    ]
    'where' :  'id' : 2 
 )
.complete( function( error, result ) 
    if( error ) 
        console.log( error );
    
    else 
        console.log( result );
    
 );

如果你使用的是下划线id字段名称,比如organization_id,你可以在创建模型时指定“underscored: true”,这样你在创建关联时就不必指定外键字段了。

【讨论】:

好建议。谢谢!我按照您所说的进行了选择,而是选择了用户并包括组织,然后是接收者,我在接收者上找到了组织,然后是用户,然后我在用户上找到了包含 ID 的位置。无论哪种方式,它使用的查询似乎都相当hacky,但如果它有效,我想它会有效!再次感谢。 @mikealeonetti 很高兴它对你有用!只是想知道你为什么决定做反向选择?我的意思是接收者,然后是组织,然后是带有 where 语句的用户? 我的目标主要是获取用户可以关联的所有接收器设备。获取时我真的不需要有关组织或用户的信息。因此,不知何故,在接收者表上执行查找/选择以首先获得这些对我来说更有意义。否则我必须在查找中得到结果,得到组织,然后得到接收者。如果这仍然有意义:D.

以上是关于Sequelize belongsToMany 关联不通过表工作的主要内容,如果未能解决你的问题,请参考以下文章

Sequelize Find belongsToMany 关联

在 sequelize.js 中获取与 belongsToMany 的关联

Sequelize belongsToMany 关联不通过表工作

使用自定义连接表主键 Sequelize BelongsToMany

Sequelize 重复键约束违规

Sequelize 查询在多对多关系中显示附加数据