2

I am developing a questionnaire in MERN stack - one question per page (e.g. "Specify name" on one page, click next question, "Specify company name" on another page etc.), about 40 pages.

When clicking "Next" the app saves user's answer in the localStorage, retrieves from localStorage and sends an axios.post to express server, which finds a MongoDB document by uuid and updates it with a new answer.

The problem is that not all answers are saved in the MongoDB. After some questions the answers stop saving to MongoDB. Only when I restart the express server and try again to answer the question, then it saves it to MongoDB.

I have no idea what's wrong. Any suggestions are welcome

Here is a code example:

//React:
import { useState } from "react";
import axios from "axios";
import { useHistory } from "react-router-dom";
import NextQuestion from "./NextQuestion";

export default function Question1() {
  const history = useHistory();
  const [input, setInput] = useState("");

  function handleChange(e) {
    setInput(e.target.value);
  }

  function handleSubmit(e) {
    e.preventDefault();
    localStorage.setItem("name", input);

    const data = {
      uuid: localStorage.getItem("uuid"),
      name: localStorage.getItem("name"),
    };

    axios.post("/answers", data);

    history.push("/next-question");
  }

  return (
    <BrowserRouter>
      <Route path="/question-1">
        <form>
          <input id="name" type="text" value={value} onChange={handleChange} />
          <label for="#name">Please specify your name</label>
          <button onClick={handleSubmit}>NEXT QUESTION</button>
        </form>
      </Route>
      <Switch>
        <Route path="/next-question">
          <NextQuestion />
        </Route>
      </Switch>
    </BrowserRouter>
  );
}

//Express server:
require("dotenv").config();
const express = require("express");
const app = express();
const cors = require("cors");
const mongoose = require("mongoose");

app.use(express.json());
app.use(cors());

mongoose.connect(process.env.MONGO_URI);

const answerSchema = {
  uuid: String,
  name: String,
  company: String,
  title: String,
  email: String,
  phone: String,
};

const Answer = mongoose.model("Answer", answerSchema);

app.post("/answers", (req, res) => {
  if (req.body.uuid) {
    Answer.updateOne(
      { uuid: req.body.uuid },
      {
        name: req.body.name,
        company: req.body.company,
        title: req.body.title,
        email: req.body.email,
        phone: req.body.phone,
      },
      {
        upsert: true,
      }
    )
      .then((item) => console.log(item))
      .catch((err) => res.status(400).json("Error " + err));
  } else {
    const newAnswer = new Answer({
      uuid: req.body.uuid,
      name: req.body.name,
      company: req.body.company,
      title: req.body.title,
      email: req.body.email,
      phone: req.body.phone,
    });

    newAnswer
      .save()
      .then((item) => console.log(item))
      .catch((err) => res.status(400).json("Error " + err));
  }
});

app.listen(3001, function () {
  console.log("Express is running");
});
Marina Kim
  • 75
  • 6
  • When does it occur exactly? Randomly skips answers or always the same ones? Do you get any error? How do you assign uuid to the user? – kmp Sep 28 '21 at 13:54
  • @kmp, hi, after many tests I noticed it saves questions 1-4, and then from question 5 it stops saving.. then I restart the express server and it saves questions 5 to approx. 9.. I can say after question 5 it's quite randomly. Up to question 5 everything works. I don't get any errors. Uuid is assigned in App.js through useEffect(() => { const id = uuidv4(); localStorage.setItem("uuid", id); }, []); – Marina Kim Sep 28 '21 at 14:27
  • 2
    Try this: https://stackoverflow.com/a/24711713/13747848 and also remove the if-else statement because you're using `{ upsert: true }` which means it'll create a new object if it doesn't exist. – kmp Sep 28 '21 at 15:27
  • Intuition guess: instead of maintaining a single connection to Mongo from Express try to connect separately for every single save, disconnecting after each of them. – Joel Peltonen Sep 28 '21 at 17:05
  • @kmp, it worked! I removed the if/else statement and used findOneAndUpdate method ☺️ Please post your solution as an answer so I could accept it – Marina Kim Sep 29 '21 at 03:31

1 Answers1

1

Original answer: How do I update/upsert a document in Mongoose?

Please make sure to give credit to the original respondent


Mongoose now supports this natively with findOneAndUpdate (calls MongoDB findAndModify).

The { upsert: true } option creates the object if it doesn't exist. defaults to false.

var query = {'username': req.user.username};
req.newData.username = req.user.username;

MyModel.findOneAndUpdate(query, req.newData, {upsert: true}, function(err, doc) {
    if (err) return res.send(500, {error: err});
    return res.send('Succesfully saved.');
});

In older versions Mongoose does not support these hooks with this method:

  • defaults
  • setters
  • validators
  • middleware
kmp
  • 692
  • 6
  • 17