skip to Main Content

In the development of my fullstack aplication (which is a facebook clone) i’ve found this error in my server, and i don’t know how to solve it.

I’m using node.js, express, mongodb, mongoose and typescript, and, in the development of the route for liking publications is where this error took place (as well in the liking comments route).

Error

VersionError: No matching document found for id "60bf5b73de309f1a30fe88a2" version 10 modifiedPaths "likes"
    at generateVersionError (C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendnode_modulesmongooselibmodel.js:432:10)
    at model.Model.save (C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendnode_modulesmongooselibmodel.js:488:28)
    at C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendsrccontrollerspublication.ts:166:18
    at Generator.next (<anonymous>)
    at fulfilled (C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendsrccontrollerspublication.ts:5:58)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:93:5) {
  version: 10,
  modifiedPaths: [ 'likes' ]
}
VersionError: No matching document found for id "60bf5b73de309f1a30fe88a2" version 10 modifiedPaths "likes"
    at generateVersionError (C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendnode_modulesmongooselibmodel.js:432:10)
    at model.Model.save (C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendnode_modulesmongooselibmodel.js:488:28)
    at C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendsrccontrollerspublication.ts:166:18
    at Generator.next (<anonymous>)
    at fulfilled (C:Usersdiego cifuentesDesktopPortafolioFullstack ProjectsFacebook - MERN ( with next.js )backendsrccontrollerspublication.ts:5:58)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:93:5) {
  version: 10,
  modifiedPaths: [ 'likes' ]
}

This only happens when the user in the client side tries to click like button too fast multiple times, so, because of that, the problem doesn’t give the action enough time to interact with the server.

I’ve looked for a solution, and i’ve seen that people mention .update() instead of .save in this cases, but, i can’t really understand specifycally what .update() means and why it might be a solution for this problem.

To give you a litle bit more of context, this is how the logic looks like for the liking pubs route

// Like Publication

export const likePublication = async (req: Request, res: Response) => {
  const { publicationId } = req.params;

  const { identifier } = req.body;

  // Check id's

  if (!mongoose.Types.ObjectId.isValid(identifier!))
    return res.status(400).json({ Message: "identifier not valid" });

  if (!mongoose.Types.ObjectId.isValid(publicationId!))
    return res.status(400).json({ Message: "identifier not valid" });

  // Find pub

  const thePub: Ipub = await Publication.findById(publicationId);

  // Find user

  const theUser: Iauth = await User.findById(identifier);

  try {
    // Check if user already liked, if not, like the pub
    if (thePub.likes!.find(f => f.identifier === theUser.id) === undefined) {
      thePub.likes!.push({ identifier: theUser.id! });
    }
    // Check if user already liked, if user liked, cut like
    else if (thePub.likes!.find(f => f.identifier === theUser.id)) {
      thePub.likes = thePub.likes!.filter(
        filt => filt.identifier !== theUser.id!
      );
    }

    // Save

    await thePub.save();

    return res.json(thePub);
  } catch (err) {
    console.log(err);
    return res.status(500).json({ Error: "the API failed" });
  }
};

What can i do ? thanks !

2

Answers


  1. Since you control the full-stack, in the frontend part, you can use BlockUI to block the screen when a request is being sent to the server. This will prevent users from doing multiple requests when a request is treated and has not been finished yet.

    Login or Signup to reply.
  2. MongoDB will auto-increment the version number of a document when you save it.
    Before the save action, it will compare the version number of the incoming document and the existing document in the collection. If the incoming document version is lower than the version in the collection it will throw the "No matching document found" error. When a user clicks the like button very fast await Publication.findById(publicationId); might not return the latest document since the previous save action might not be completed. One way of handling this issue is to set a debounce time in calling likePublication route from the frontend. Otherwise, you have to catch this error and try to like again.

    // Like Publication
    const maxRetry = 3;
    async function likePublication(publicationId:ObjectId, identifier:ObjectId, retryCount = 0) {
      if(retryCount > maxRetry) {
        throw new Error("Max retry reached");
      }
      // Find pub
    
      const thePub: Ipub = await Publication.findById(publicationId);
    
      // Find user
    
      const theUser: Iauth = await User.findById(identifier);
    
      try {
        // Check if user already liked, if not, like the pub
        if (thePub.likes!.find(f => f.identifier === theUser.id) === undefined) {
          thePub.likes!.push({ identifier: theUser.id! });
        }
        // Check if user already liked, if user liked, cut like
        else if (thePub.likes!.find(f => f.identifier === theUser.id)) {
          thePub.likes = thePub.likes!.filter(
            filt => filt.identifier !== theUser.id!
          );
        }
    
        // Save
    
        return thePub.save();
      } catch (err) {
        if(err.message.indexOf("No matching document found") > -1) {
          return likePublication(publicationId, identifier, retryCount+1);
        }
        throw err;
      }
    }
    
    export const likePublicationHandler = async (req: Request, res: Response) => {
      const { publicationId } = req.params;
    
      const { identifier } = req.body;
    
      // Check id's
    
      if (!mongoose.Types.ObjectId.isValid(identifier!))
        return res.status(400).json({ Message: "identifier not valid" });
    
      if (!mongoose.Types.ObjectId.isValid(publicationId!))
        return res.status(400).json({ Message: "identifier not valid" });
      try {
        const thePub = await likePublication(publicationId, identifier);
    
        return res.json(thePub);
      } catch (err) {
        console.log(err);
        return res.status(500).json({ Error: "the API failed" });
      }
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search