#node.js #postgresql #express #sequelize.js
#node.js #postgresql #выразить #sequelize.js
Вопрос:
У меня возникли проблемы с воссозданием следующего запроса в Sequelize. Я сидел часами, пытаясь разобраться в этом.
Я использую camelCase вместо snake_case, поэтому я не могу повторно использовать один и тот же запрос.
Запрос не сработает, если я заменю все переменные snake_cased на camelCase в запросе. Я возвращаю «отношение»directmessages «не существует». Я не могу получить доступ к таблице directmessages в psql с помощью ТАБЛИЦЫ directmessages; — но я знаю, что она должна быть там.
Я также не могу понять, как выполнить тот же запрос с sequelize.
В принципе, мне нужно получить каждого пользователя, с которым текущий пользователь уже напрямую связался. Либо в качестве отправителя, либо получателя.
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',
})
}
Я попытался создать запрос с sequelize следующим образом:
models.User.findAll({
include:[{
model: models.DirectMessage,
where: {
teamId,
[models.sequelize.Op.or]: [{senderId: user.id}, {receiverId: user.id}]
}
}]
}, { raw: true })
Я получаю обратно «сообщение»: «directMessage не связан с пользователем!», что, я полагаю, связано с тем, что DirectMessage связан с пользователем, но не наоборот.
Есть ли у кого-нибудь какие-либо советы о том, как я могу восстановить этот запрос?
Комментарии:
1. Пытался удалить базу данных, воссоздав все данные. При попытке извлечь directMessageMembers выдается следующая ошибка: «сообщение»: «отношение «directmessages» не существует»
Ответ №1:
я полагаю, это потому, что DirectMessage связан с 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….
Ответ №2:
Здесь есть пара моментов. Во-первых, когда вы используете 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',
})
}
Теперь, чтобы иметь возможность использовать имена camelCase в javascript и sequelize и сохранить snake_case в sql, вы можете сделать это:
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
}
}
}
И последняя проблема, которая у вас возникает с включением, заключается в том, что вам нужно указать, какую ассоциацию вы вызываете, и, как вы сказали, вам нужно
объявить ассоциацию другим способом, от User
к DirectMessage
:
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
поэтому фильтр senderId
и receiverId
не имеет особого смысла.
В любом случае, надеюсь, что с этим есть лучшая идея, что делать.