简体   繁体   中英

Sequelize not retrieving all data after insert

I have noticed that my backend is not retrieving the expected data after an insert. In my React application, I have one function which inserts data into the database and after getting a response, a new request is sent to update the current component state with the newly fetched data. All my functions are using await/async and in the backend, all transactions are correctly used and committed in order.

My client is calling the following endpoints: -POST: api/ticket ( INSERT AN ITEM) -GET: api/ticket (GET ALL ITEMS)

Here is what the backend is showing which looks correct to me, the problem is that in the 'SELECT' statement, the inserted item is not retrieved. The transactions are started from two different routes but I don't see why it should be an issue. In addition, I tried to change the AddItem function to output the same findAll statement which is called when using the GET method and the data returned are correct. So why if I separate these two flows I do not get all the items? I always need to refresh the page to get the added item.

START TRANSACTION;
Executing (a9d14d5c-c0ac-4821-9b88-293b086debaa): INSERT INTO `messages` (`id`,`message`,`createdAt`,`updatedAt`,`ticketId`,`userId`) VALUES (DEFAULT,?,?,?,?,?);
Executing (a9d14d5c-c0ac-4821-9b88-293b086debaa): COMMIT;
Executing (9ee9ddaa-294e-41d1-9e03-9f02a2737030): START TRANSACTION;
Executing (9ee9ddaa-294e-41d1-9e03-9f02a2737030): SELECT `ticket`.`id`, `ticket`.`subject`, `ticket`.`status`, `ticket`.`createdAt`, `ticket`.`updatedAt`, `ticket`.`deletedAt`, `ticket`.`userId`, `messages`.`id` AS `messages.id`, `messages`.`message` AS `messages.message`, `messages`.`sender` AS `messages.sender`, `messages`.`createdAt` AS `messages.createdAt`, `messages`.`updatedAt` AS `messages.updatedAt`, `messages`.`deletedAt` AS `messages.deletedAt`, `messages`.`ticketId` AS `messages.ticketId`, `messages`.`userId` AS `messages.userId`, `messages->user`.`id` AS `messages.user.id`, `messages->user`.`firstname` AS `messages.user.firstname`, `messages->user`.`surname` AS `messages.user.surname`, `messages->user`.`email` AS `messages.user.email`, `messages->user`.`password` AS `messages.user.password`, `messages->user`.`stripeId` AS `messages.user.stripeId`, `messages->user`.`token` AS `messages.user.token`, `messages->user`.`birthDate` AS `messages.user.birthDate`, `messages->user`.`status` AS `messages.user.status`, `messages->user`.`confirmationCode` AS `messages.user.confirmationCode`, `messages->user`.`createdAt` AS `messages.user.createdAt`, `messages->user`.`updatedAt` AS `messages.user.updatedAt`, `messages->user`.`deletedAt` AS `messages.user.deletedAt` FROM `tickets` AS `ticket` LEFT OUTER JOIN `messages` AS `messages` ON `ticket`.`id` = `messages`.`ticketId` AND (`messages`.`deletedAt` IS NULL) LEFT OUTER JOIN `users` AS `messages->user` ON `messages`.`userId` = `messages->user`.`id` AND (`messages->user`.`deletedAt` IS NULL) WHERE (`ticket`.`deletedAt` IS NULL);
Executing (9ee9ddaa-294e-41d1-9e03-9f02a2737030): COMMIT;

-- POST '/api/ticket

exports.addMessage = async (req, res) => {
  try {
    const result = await sequelize.transaction(async (t) => {
      var ticketId = req.body.ticketId;
      const userId = req.body.userId;
      const message = req.body.message;
      const subject = req.body.subject;

      // Validate input - If new ticket, a subject must be provided
      if (!ticketId && !subject) {
        return res
          .status(400)
          .send({ message: "New ticket must have a subject" });
      }
      // Validate input - If ticket exists, userId and message must be provided
      if (!userId && !message && ticketId) {
        return res
          .status(400)
          .send({ message: "UserID and message are required" });
      }
      // Create ticket is no ticketID was provided
      if (!ticketId) {
        const [ticket, created] = await Ticket.findOrCreate({
          where: {
            subject: subject,
            userId: userId,
          },
          transaction: t,
        });
        ticketId = ticket.id;
      }
      // Create a new message object
      const messageObject = await db.message.create(
        {
          message: message,
          userId: userId,
          ticketId: ticketId,
        },
        { transaction: t }
      );
      // Output message object
      return res.send(messageObject);
    });
  } catch (err) {
    console.log(err);
    return res.status(500).send({
      message:
        err.message || "Some error occurred while creating the ticket message.",
    });
  }
};

-- GET: api/ticket

exports.findAll = async (req, res) => {
  try {
    const result = await sequelize.transaction(async (t) => {
      const tickets = await db.ticket.findAll(
        {
          include: [{ model: db.message, include: [db.user] }],
        },
        { transaction: t }
      );
      tickets.forEach((ticket) => {
        console.log(JSON.stringify(ticket.messages.length));
      });

      return res.send(tickets);
    });
  } catch (err) {
    console.log(err);
    res.status(500).send({
      message: err.message || "Some error occurred while retrieving Tickets.",
    });
  }
};

You sent a response to a client before the transaction actually was committed. You just need to move res.send(messageObject); outside the transaction call.
You can try to look what's going on in the current version of your code if you add several console.log with messages to see what the actual order of actions is (I mean a couple of messages in POST (the last statement inside transaction and after transaction before res.send ) and at least one at the beginning of GET).

Actually if the transaction was rolled back you'd send an uncommited and already removed object/record that I suppose is not your goal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM