如何获取每个用户的对话并包含消息?

Posted

技术标签:

【中文标题】如何获取每个用户的对话并包含消息?【英文标题】:How to get the conversations for each user and include the messages? 【发布时间】:2021-03-18 14:26:59 【问题描述】:

我正在尝试让每个用户的对话显示在我前端的收件箱屏幕上。我可以将消息发布到数据库,但是当我尝试获取它们时,我一直在获取

[SequelizeEagerLoadingError]: Message is not associated to Conversation!

有人可以看看我的代码吗?

这是我的获取请求:

router.get('/', auth, (req, res) => 
  Conversation.findAll(
    where: 
      [Op.or]: [
        
          user1:  [Op.eq]: req.user.id ,
          user2:  [Op.eq]: req.user.id ,
        ,
      ],
    ,
    include: [ model: Message ],
  )
    .then(() => res.send())
    .catch((err) => console.log(err));
);

这是我的对话模型

const Conversation = db.define('Conversation', 
);

module.exports = Conversations;

Conversation.associate = (models) => 
  Conversation.hasMany(models.Message, 
    foreignKey: 'conversationId',
  );

  Conversation.belongsTo(models.Post, 
    foreignKey: 'PostId',
  );
;

User.hasMany(Conversation, 
  foreignKey: 'user1',
);

User.hasMany(Conversation, 
  foreignKey: 'user2',
);

这是我的消息模型:

const Message = db.define('Message', 
  id: 
    primaryKey: true,
    type: Sequelize.INTEGER,
  ,
  senderId: 
    type: Sequelize.STRING,
  ,
  receiverId: 
    type: Sequelize.STRING,
  ,
  message: 
    type: Sequelize.STRING,
  ,
  conversationId: 
    type: Sequelize.INTEGER,
  ,
);

module.exports = Message;

User.hasMany(Message, 
  foreignKey: 'senderId',
  as: 'SentMessage',
);

User.hasMany(Message, 
  foreignKey: 'receiverId',
  as: 'ReceivedMessage',
);

Message.associate = (models) => 
  Message.belongsTo(models.User, 
    foreignKey: 'senderId',
    as: 'Sender',
  );

  Message.belongsTo(models.User, 
    foreignKey: 'receiverId',
    as: 'Receiver',
  );

  Message.belongsTo(models.Conversation, 
    foreignKey: 'conversationId',
  );
;

Post.hasMany(Conversation,  foreignKey: 'PostId' );

更新

删除后

Conversation.hasMany(models.Message,foreginKey:"conversationId") 

从我的对话模型中的 associate 方法并将其添加到我的消息模型中,我停止收到关联错误,但现在当我尝试测试 get 请求时,当我的数据库充满条目时,我一直得到一个空响应。

这是我更新的获取请求:

router.get('/',auth,async(req,res)=>
const conversation = await Conversations.findAll(
include:[
 model:Message,
required: false,
],
where:
[Op.or]:[
user1:[Op.eq]:req.user.id,
user2:[Op.eq]:req.user.id,
]
,
);

if(!conversation) return res.send().catch(err=>console.log(err)) 

res.status(200).send()

)

这是我在终端中的回复:

 Executing (default): SELECT "Conversation"."id", 
 "Conversation"."createdAt", "Conversation"."updatedAt", 
 "Conversation"."user1", "Conversation"."user2", 
 "Conversation"."PostId", "Messages"."id" AS "Messages.id", 
 "Messages"."senderId" AS "Messages.senderId", 
 "Messages"."receiverId" AS 
 "Messages.receiverId", 
 "Messages"."message" AS "Messages.message", 
 "Messages"."conversationId" AS "Messages.conversationId", 
 "Messages"."createdAt" AS "Messages.createdAt", 
 "Messages"."updatedAt" AS "Messages.updatedAt" FROM "Conversations" 
 AS "Conversation" LEFT OUTER 
 JOIN "Messages" AS "Messages" ON "Conversation"."id" = 
 "Messages"."conversationId" WHERE (("Conversation"."user1" = 43 AND 
 "Conversation"."user2" = 43));

【问题讨论】:

评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:

const user = require("./containers/api/config/database")

您可以进行一些改进 - 您的示例代码中的问题是您在 MessagesUser 之间有多个关系,因此您需要指定 as 关键字,以便 Sequelize 知道使用哪个。如果没有关联中的as,您就没有任何关联,因此 Sequelize 可以判断没有任何关系。

我会让 Sequelize 自动为主键和外键生成大部分列,以保持简单。当可以返回多个结果时,使用单数表名并让 Sequelize 复数也是一种很好的做法,例如 Post.getConversations()Message.getConversation()。如果可以的话,使用 async/await 而不是 thenables 也更易读。

您应该能够将where 移动到Message 包含并添加required: true 使其成为RIGHT JOIN

模型

const User = db.define('user', 
  // fields go here
);

const Post = db.define('post', 
  // fields go here
);

const Conversation = db.define('conversation', 
  // don't define columns, they will be generated
);

const Message = db.define('message', 
  message: 
    type: Sequelize.STRING,
  ,
  // more fields
);

协会

// Message -- Conversation, creates message.conversationId NOT NULL
Message.belongsTo(Conversation,  allowNull: false );
// Conversation -< Messages, uses message.conversationId
Conversation.hasMany(Message);

// Conversation -- User, creates conversation.creatorId NOT NULL
Conversation.belongsTo(User,  as: 'Creator', foreignKey: 'creatorId', allowNull: false );
// User -< Conversations, uses conversation.creatorId
User.hasMany(Conversation,  as: 'CreatedConversations', foreignKey: 'creatorId' );

// Message -- User, creates message.senderId NOT NULL
Message.belongsTo(User,  as: 'Sender', foreignKey: 'senderId', allowNull: false );
// User -< Message (Sent), join user.id = message.senderId
User.hasMany(Message,  as: 'Sent', foreignKey: 'senderId' );

// Message -- User, creates message.receiverId NOT NULL
Message.belongsTo(User,  as: 'Receiver', foreignKey: 'receiverId', allowNull: false );
// User -< Message (Received), join user.id = message.receiverId
User.hasMany(Message,  as: 'Received', foreignKey: 'receiverId' );

// Conversation -- Post, creates conversation.postId NOT NULL
Conversation.belongsTo(Post,  allowNull: false );
// Post -< Conversations, uses conversation.postId
Post.hasMany(Conversation);

查询 获取用户作为发送者或接收者在消息中的所有对话。

router.get('/', auth, async (req, res) => 
  try 
    const conversations = await Conversation.findAll(
      include: [
        model: Message,
        where: 
          [Op.or]: [
             senderId: req.user.id , 
             receiverId: req.user.id ,
          ],
        ,
        required: true, // RIGHT  JOIN
      ],
    );
    return res.json(conversations);
   catch (err) 
    console.log(err);
    return res.status(500).send(err);
  
);

查询 获取用户创建的所有对话。这将替换对话中的 user1user2,但您可能仍希望将其用于其他目的。

router.get('/created_conversations', auth, async (req, res) => 
 try 
   const conversations = await Conversation.findAll(
     include: [
       model: Message,
       required: false, // LEFT  JOIN
     ],
     where: 
       creatorId: req.user.id
     ,
   );
   return res.json(conversations);
  catch (err) 
   console.log(err);
   return res.status(500).send(err);
 
);
router.get('/user', auth, async (req, res) => 
  try 
    const user = await User.findByPk(req.user.id, 
      include: [
        model: Conversation,
        as: 'CreatedConversations',
        required: false, // LEFT  JOIN
        include: [
          model: Message,
          required: false, // LEFT  JOIN
        ],
      ],
    );

    // const conversations = user.getConversations();
    // const [conversation] = conversations; // get the first result
    // const messages = conversation.getMessages();

    return res.json(user);
   catch (err) 
    console.log(err);
    return res.status(500).send(err);
  
);

【讨论】:

嗨,感谢您回复我。这些关联应该放在每个相应的模型文件中吗?如果是的话,我已经尝试过了,我不断收到错误:Conversations.hasMany 调用了不是 Sequelize.Model 子类的东西,所以我使用了 associate 方法,当我测试获取用户创建的所有对话时,我得到了错误消息和对话不相关 @kd12345 是的,关联通常会进入模型文件,但如果您想将它们放在其他地方,它们没有必须...它们只需要初始化时调用。我确实将大多数模型更改为单数,但您的错误是复数,因此请仔细检查案例 - 您也可以将其更改回使用 MessagesConversations 等,但这可能会导致稍后在 Sequelize 复数时出现一些不直观的问题。跨度> 你能看看我发布的解决方案吗。【参考方案2】:

经过多日尝试解决这个问题并在 Anatoly 和 doublesharp 的帮助下,我终于想通了。

我的问题是我的对话模型中的关联方法由于某种我仍然不知道的原因没有被执行,所以我将它从我的对话模型中的关联方法中删除,并将它添加到我的消息模型中并且它起作用了。

这是我的代码:

消息模型:

const Message = db.define("Message", 
senderId: 
type: Sequelize.STRING,
,
receiverId: 
type: Sequelize.STRING,
,
message: 
type: Sequelize.STRING,
,
conversationId:
type: Sequelize.INTEGER,

);

module.exports = Message;

User.hasMany(Message, 
as:"SentMessage",
foreignKey: 'senderId',
);

User.hasMany(Message, 
as:"ReceivedMessage",
foreignKey: 'receiverId',
);

Message.associate = (models) => 

Message.belongsTo(models.User, 
as:"Sender",
foreignKey: "senderId",
allowNull: false 
);
Message.belongsTo(models.User, 
as:"Receiver",
foreignKey: "receiverId",
allowNull: false 
);
Message.belongsTo(models.Conversations,  allowNull: false ,
foreignKey: "conversationId",

;

Conversation.hasMany(Message,
foreignKey: "conversationId",

);

这是我的对话模型:

const Conversation = db.define("Conversation", );

module.exports = Conversation;

 User.hasMany(Conversation, 
 foreignKey: 'user1'
 );

 User.hasMany(Conversation, 
 foreignKey: 'user2'
 );

 Conversation.belongsTo(User,  as: 'Creator', foreignKey: 'user1', allowNull: 
 false )
 Conversation.belongsTo(User,  as: 'Recipient', foreignKey: 'user2', 
 allowNull: false )

这是我的帖子模型关联:

Post.hasMany(Conversation,  foreignKey: "PostId" );

Conversation.belongsTo(Post,
foreignKey: "PostId",
allowNull: false 
)

这是我的 GET 请求:

router.get('/', auth, async (req, res) => 
try 
const conversations = await Conversation.findAll(
  include: [
    model: Message,
    where: 
      [Op.or]: [
         senderId: req.user.id , 
         receiverId: req.user.id ,
      ],
    ,
    required: true, // RIGHT  JOIN
  ],
);
return res.json(conversations);
 catch (err) 
console.log(err);
return res.status(500).send(err);

);

这是我的邮递员回复:

[

    "id": 1,
    "user1": 43,
    "user2": 45,
    "PostId": 523,
    "Messages": [
        
            "id": 1,
            "senderId": 43,
            "receiverId": 45,
            "message": "My first message & Conversation",
            "conversationId": 1,
        
    ]
  ,
  
    "id": 4,
    "user1": 43,
    "user2": 45,
    "PostId": 522,
    "Messages": [
        
            "id": 7,
            "senderId": 43,
            "receiverId": 45,
            "message": "One more time",
            "conversationId": 4,
        ,
    ]
    ,
  
    "id": 5,
    "user1": 45,
    "user2": 43,
    "PostId": 518,
    "Messages": [
        
            "id": 11,
            "senderId": 45,
            "receiverId": 43,
            "message": "Hello 43",
            "conversationId": 5,
        
    ]

]

【讨论】:

以上是关于如何获取每个用户的对话并包含消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 powershell 从 lync 对话中获取消息?

从每个对话中获取最后一条消息

如何在 Relay Modern 中强制获取

如何使用 XMPP ios8 获取最后一个对话用户?

如何从消息表中获取对话列表?

如何从 mysql 数据库中获取数据并使用 PHP 将其发送给用户? [关闭]