使用sequelize构造查询问题

时间:2019-03-06 00:32:26

标签: node.js postgresql express sequelize.js

我在Sequelize中重新创建以下查询时遇到问题。我已经坐了几个小时,试图弄清楚这一点。

我使用的是camelCase而不是snake_case,所以我无法重用相同的查询。

如果我将所有snake_cased变量交换为查询中的camelCase,则该查询将不起作用。我回来“关系\“ directmessages \”不存在”。我无法使用TABLE directmessages访问psql中的directmessages表; -但我知道它应该在那里。

我也不知道如何用续集进行相同的查询。

基本上,我需要获取当前用户已经直接发送消息的每个用户。作为发送者或接收者。

  models.sequelize.query(
    'select distinct on (u.id) u.id, u.username from users as u join direct_messages as dm on (u.id = dm.sender_id) or (u.id = dm.receiver_id) where (:currentUserId = dm.sender_id or :currentUserId = dm.receiver_id) and dm.team_id = :teamId',
    {
      replacements: { currentUserId: user.id, teamId: id },
      model: models.User,
      raw: true,
    },

这些是与此查询相关的模型:

用户模型:

User.associate = (models) => {
    User.belongsToMany(models.Team, {
        through: models.Member,
        foreignKey: 'userId',
    })
    User.belongsToMany(models.Channel, {
        through: 'channel_member',
        foreignKey: 'userId',
    })

}

DirectMessage模型:

DirectMessage.associate = (models) => {
    DirectMessage.belongsTo(models.Team, {
        foreignKey: 'teamId',
    })
    DirectMessage.belongsTo(models.User, {
        foreignKey: 'receiverId',
    })
    DirectMessage.belongsTo(models.User, {
        foreignKey: 'senderId',
    })
}

我尝试使用以下续集创建查询:

models.User.findAll({ 
            include:[{
                model: models.DirectMessage,
                where: {                        
                    teamId, 
                    [models.sequelize.Op.or]: [{senderId: user.id}, {receiverId: user.id}]
                }
            }]
            }, { raw: true })

我得到“ message”:“ directMessage与用户无关!”,我认为这是因为DirectMessage与User相关联,而不是相反。

有人对我如何重构此查询有任何提示吗?

2 个答案:

答案 0 :(得分:0)

  

我认为这是因为DirectMessage是与User相关联的,而不是与User相关联的。

我也想这样。从用户关联到DirectMessage很容易(两次):

User.hasMany(models.DirectMessage, {foreignKey: 'receiverId', as: 'receivers'});        
User.hasMany(models.DirectMessage, {foreignKey: 'senderId', as: 'senders'});        

然后查询还不错。请注意,“ as”值告诉Sequelizer使用哪个FK,因此请确保hasMany与查询的包含模型匹配

    models.Users.findAll({
        include: [
            {
                model: models.DirectMessage, as: 'receivers',
                attributes:  [[Sequelize.fn('count', 'id'), 'number_received']]
            },
            {
                model: models.DirectMessage, as: 'senders',
                attributes: [[Sequelize.fn('count', 'id'), 'number_sent']]
            }
            ],
        where : {id : user.id}, // parameter
        group : ['id']
    })        

然后,您必须验证“ senders.number_sent”或“ receivers.number_received”不是非零且> 0。从理论上讲,您可以使用HAVING子句来执行此操作,但是恕我直言,这在Sequelize中实现得不太好。...

答案 1 :(得分:0)

这里有几件事。首先,当您使用belongsToMany时,您需要在两个模型上进行关联,因为这是M:N关系,如下所示: 另外,您在关联上有错误的foreignKey。应该是这样的:

User.associate = (models) => {
  User.belongsToMany(models.Team, {
      through: models.Member,
      foreignKey: 'user_id',
  })

  models.Team.belongsToMany(User, {
      through: models.Member,
      foreignKey: 'team_id',
  })

  // ----------------------------------
  User.belongsToMany(models.Channel, {
      through: 'channel_member',
      foreignKey: 'user_id',
  })

  models.Channel.belongsToMany(user, {
      through: 'channel_member',
      foreignKey: 'channel_id',
  })

}

现在可以在javascript上使用camelCase名称并在sql上进行续集和保留snake_case,您可以执行以下操作:

module.exports = (sequelize, DataTypes) => {
  const Member = sequelize.define('Member', {
    // here goes your regular fields
    userId: { //now you can use this property on sequelize
      field: 'user_id', //and is linked yo the foreignKey
      type: DataTypes.INTEGER
    },
    teamId: {
      field: 'team_id',
      type: DataTypes.INTEGER
    }
  }
}

与include有关的最后一个问题是,因为您必须指定要调用的关联,并且正如您所说,您需要 以另一种方式从UserDirectMessage声明关联:

User.hasMany(models.DirectMessage, { //there is also hasOne()
  as: 'Sender', // this is important because you have two association from User to  DirectMessage
  foreignKey: 'sender_id',
})

User.hasMany(models.DirectMessage, { //there is also hasOne()
  as: 'Receiver', // this is important because you have two association from User to  DirectMessage
  foreignKey: 'user_id',
})

现在您可以进行查询

models.User.findAll({ 
  include:[{
      model: models.DirectMessage,
      as: 'Sender'
      where: {                        
          teamId,
      }
  }]
}, { raw: true })

我对此查询有疑问,因为实际上您正在调用所有DirectMessages,因此senderIdreceiverId过滤器没有多大意义。

无论如何,希望对此有个更好的主意。