Nodejs Data not saving on MongoDB

When i make a post request from my postman, it sends the request, returns a 201 success code, but nothing is saved on my database, it returns an empty value. Here is my App.js Code,

const express = require("express");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const authRoute = require("./routes/auth");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const passport = require("passport");
const flash = require("express-flash");
const session = require("express-session");
const cors = require("cors");
require("./config/passport");
require("./config/google-config");
require("./config/facebook-config");

dotenv.config();

mongoose.set("strictQuery", false);
mongoose
  .connect(process.env.MONGO_URL)
  .then(() => console.log("connected to db"))
  .catch((e) => console.log(e));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(
  session({
    secret: "***",
    resave: false,
    saveUninitialized: true,
  })
);
app.use(cors());
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use("/api/user", authRoute);
app.listen(3000, () => console.log("Server up and running"));

My Auth Code

const express = require("express");
const router = express.Router();
const User = require("../model/users");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const { registerValidation, loginValidation } = require("../validation");
const passport = require("passport");
require("../config/passport");
require("../config/google-config");
require("../config/facebook-config");

//register-user
router.post("/register", async (req, res) => {
  const { error } = registerValidation(req.body);
  if (error) return res.status(400).send(error.details[0].message);
  //check if user is registered
  const emailExist = await User.findOne({ email: req.body.email });
  if (emailExist) return res.status(400).send("Email already exist");
  //hashpassword
  const salt = await bcrypt.genSalt(10);
  const hashedPassword = await bcrypt.hash(req.body.password, salt);
  //createUser
  const user = new User({
    name: req.body.name,
    email: req.body.email,
    password: hashedPassword,
    phoneNumber: req.body.phoneNumber,
  });
  try {
    const savedUser = await user.save();
    res.send({ user: user._id });
  } catch (err) {
    res.status(400).send(err);
  }
});
//login
router.post("/login", async (req, res) => {
  const { error } = loginValidation(req.body);
  if (error) return res.status(400).send(error.details[0].message);
  const userExist = await User.findOne({ email: req.body.email });
  if (!userExist) return res.status(400).send("Email or Password Invalid");
  const validPassword = await bcrypt.compare(
    req.body.password,
    userExist.password
  );
  if (!validPassword) return res.status(400).send("Invalid Password");
  //create and assign a token
  const token = jwt.sign({ _id: User._id }, process.env.TOKEN_SECRET);
  res.header("auth-token", token).send(token);
  res.send("Signed In Successfully");
});
router.get(
  "/auth/google",
  passport.authenticate("google", {
    scope: ["profile", "email"],
  })
);
router.get(
  "/auth/google/callback",
  passport.authenticate("google", {
    failureRedirect: "/failed",
  }),
  function (req, res) {
    res.redirect("/success");
  }
);
router.get("/auth/facebook", passport.authenticate("facebook"));
router.get(
  "/auth/facebook/callback",
  passport.authenticate("facebook", { failureRedirect: "/login" }),
  (req, res) => {
    res.redirect("/");
  }
);
const isLoggedIn = (req, res, next) => {
  req.user ? next() : res.sendStatus(401);
};
router.get("/failed", (req, res) => {
  res.send("Failed");
});
router.get("/success", isLoggedIn, (req, res) => {
  res.send(`Welcome ${req.user.email}`);
});


router.post("/:_id/books/current-reading", async (req, res) => {
  const {
    bookTitle,
    bookAuthor,
    totalPages,
    pagesLeft,
    daysLeft,
    bookGenre,
    bookCompleted,
  } = req.body;
  const user = await User.findById(req.params._id);
  if (!user) return res.status(404).send("User not found");
  user.bookReading.currentReading = {
    ...user.bookReading.currentReading,
    bookTitle: bookTitle,
    bookAuthor: bookAuthor,
    totalPages: totalPages,
    pagesLeft: pagesLeft,
    daysLeft: daysLeft,
    bookGenre: bookGenre,
    bookCompleted: bookCompleted,
  };
  const savedUser = await user.save();
  res.status(200).json(savedUser);
});
module.exports = router;

And my schema

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const bookReadingSchema = new Schema({
  pagesLeft: {
    type: Number,
    default: 0,
  },
  bookCompleted: {
    type: Boolean,
    default: false,
  },
  daysLeft: {
    type: Number,
    default: 0,
  },
  bookTitle: {
    type: String,
    default: "",
  },
  totalPages: {
    type: Number,
    default: 0,
  },
  bookAuthor: {
    type: String,
    default: "",
  },
  bookGenre: {
    type: String,
    default: "",
  },
});

const bookReadingDefault = {
  pagesLeft: 0,
  bookCompleted: false,
  daysLeft: 0,
  bookTitle: "",
  totalPages: 0,
  bookAuthor: "",
  bookGenre: "",
};

const userSchema = new Schema(
  {
    name: {
      type: String,
      minlength: 6,
      maxlength: 255,
    },
    email: {
      type: String,
      maxlength: 255,
      unique: true,
    },
    phoneNumber: {
      type: String,
    },
    password: {
      type: String,
      minlength: 6,
      maxlength: 1024,
    },
    bookReading: {
      currentReading: {
        type: bookReadingSchema,
        default: bookReadingDefault,
      },
    },
  },
  { timestamps: true }
);

module.exports = mongoose.model("User", userSchema);

Will appreciate any help greatly.

Hi :wave: @Ojochogwu_Dickson,

Welcome to the MongoDB Community forums :sparkles:

I preassume that you are hitting the /register route to create a user.

The above code will return an empty response instead of the expected JSON object containing the user ID because the savedUser variable is never used in the response. Instead, the response uses the user variable, which is the new user instance that doesn’t contain the _id.

So, to resolve this error, please modify the code to:

const savedUser = await user.save();
res.send({ user: savedUser._id });

If it doesn’t work as expected, please post more details regarding the error, and the workflow you’re doing.

Regards,
Kushagra

ok, hi. Thanks. The user register is going well, the data is getting saved, i think the problem is with my schema, i need to create a different schema to save the book reading records and not append it to the main user profile schema, since the book reading records is supposed to be independent, that’s what i am thinking.

1 Like

Hi, i hope you can help me with this please, here is what i’m trying to achieve with the schema, the user should be able to add a book records to their account. Do i really need to create a new schema for the book records? looking at my current schema referenced in the main post, what do you think i should do?. I’m still very much confused.

Hi :wave: @Ojochogwu_Dickson,

Before answering your question, may I ask how you intend to access the data?

The general rule of thumb when modeling your data in MongoDB is - “Data that is accessed together should be stored together.

  1. Could you please clarify why you think it’s not supposed to be added to the user profile, and what you mean by "independent" in this context?

  2. Rather than jumping straight into the solution, could you explain the typical scenario and workflow of this app?

Best,
Kushagra

ok, here is how it is supposed to work. The user can create an account using the profile details, the user should be able to create, and add books he is currently working on to his account. He can add as much books as possible, hence an array of books. For the “independent”, i probably mean, the book addition to the user account should not be part of the register schema.

Hi :wave: @Ojochogwu_Dickson,

Thanks for explaining the workflow of the app.

As I understand you frequently need to access the books and their progress for a particular user.

Considering this it can be useful to design your schema to store the book details as an array within the userSchema and using .populate() functionality you can access the book’s details if you need.

const userSchema = new Schema(
    {
        name: {
            type: String,
            minlength: 6,
            maxlength: 255,
        },
        email: {
            type: String,
            maxlength: 255,
            unique: true,
        },
        phoneNumber: {
            type: String,
        },
        password: {
            type: String,
            minlength: 6,
            maxlength: 1024,
        },
        books: [
            {
                type: Schema.Types.ObjectId,
                ref: 'Book'
            }
        ],
    },
    { timestamps: true }
);

module.exports = mongoose.model("User", userSchema);

In the above schema books field is part of the userSchema which is storing the book _id in an array format as a reference to the book schema.

Here is the bookSchema. Sharing this for your reference:

const bookSchema = new Schema({
    title: {
        type: String,
        required: true
    },
    author: {
        type: String,
        required: true
    },
    genre: {
        type: String,
        required: true
    },
    totalPages: {
        type: Number,
        required: true
    },
    pagesLeft: {
        type: Number,
        default: 0,
    },
    completed: {
        type: Boolean,
        default: false,
    },
});

module.exports = mongoose.model("Book", bookSchema);

This is just an example solution, and its effectiveness depends on the specific use case.

To determine the optimal solution, it is recommended to evaluate the performance with expected workloads. One approach is to use mgeneratejs to generate randomized data for testing purposes.

I hope it helps!

Best,
Kushagra

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.