Hamza Siddiqui
Hamza Siddiqui

Reputation: 155

Mongoose cannot find the desired output

I have three schemas.

User.js:

const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
  },
  email: {
    type: String,
    unique: true,
    required: true,
  },
  password: {
    type: String,
    required: true,
  },
});

userSchema.pre("save", function (next) {
  const user = this;
  if (!user.isModified("password")) {
    return next();
  }

  bcrypt.genSalt(10, (err, salt) => {
    if (err) {
      return next(err);
    }
    bcrypt.hash(user.password, salt, (err, hash) => {
      if (err) {
        return next(err);
      }
      user.password = hash;
      next();
    });
  });
});

userSchema.methods.comparePassword = function (candidatePassword) {
  const user = this;
  return new Promise((resolve, reject) => {
    bcrypt.compare(candidatePassword, user.password, (err, isMatch) => {
      if (err) {
        return reject(err);
      }

      if (!isMatch) {
        return reject(false);
      }

      resolve(true);
    });
  });
};

mongoose.model("User", userSchema);

Project.js:

const mongoose = require("mongoose");

const diamondSchema = new mongoose.Schema({
  criteria: {
    novelty: String,
    technology: String,
    complexity: String,
    pace: String,
  },
});

const projectSchema = new mongoose.Schema({
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
  },
  projectName: {
    type: String,
    default: "",
  },
  projectBudget: {
    type: Number,
  },
  projectDuration: {
    type: Number,
  },
  industry: {
    type: String,
  },
  companyName: {
    type: String,
  },
  numberOfEmployees: {
    type: Number,
  },
  diamond: [diamondSchema],
});

mongoose.model("Project", projectSchema);

Recommendation.js:

const mongoose = require("mongoose");

const diamondSchema = new mongoose.Schema({
  criteria: {
    novelty: String,
    technology: String,
    complexity: String,
    pace: String,
  },
});

const recommendationSchema = new mongoose.Schema({
  diamond: [diamondSchema],
  description: {
    type: String,
  },
});

mongoose.model("Recommendation", recommendationSchema);

And two route files.

authRoutes.js:

const express = require("express");
const mongoose = require("mongoose");
const User = mongoose.model("User");
const jwt = require("jsonwebtoken");

const router = express.Router();

router.post("/signup", async (req, res) => {
  const { name, email, password } = req.body;

  try {
    const user = new User({ name, email, password });

    await user.save();

    const token =
      //token has payload-->user id
      jwt.sign({ userId: user._id }, "MY_SECRET_KEY");

    res.send({ token });
  } catch (err) {
    //invalid data
    return res.status(422).send(err.message);
  }
});

router.post("/signin", async (req, res) => {
  const { email, password } = req.body;

  if (!email || !password) {
    return res.status(422).send({ error: "Must provide email and password" });
  }
  const user = await User.findOne({ email });
  if (!user) {
    return res.status(404).send({ error: "Invalid email or password" });
  }

  try {
    await user.comparePassword(password);
    const token = jwt.sign({ userId: user._id }, "MY_SECRET_KEY");
    res.send({ token });
  } catch (err) {
    return res.status(422).send({ error: "Invalid email or password" });
  }
});

module.exports = router;

projectRoutes.js:

const express = require("express");

const mongoose = require("mongoose");

const requireAuth = require("../middlewares/requireAuth");

const Project = mongoose.model("Project");
const Recommendation = mongoose.model("Recommendation");
const router = express.Router();

router.use(requireAuth);

router.get("/projects", async (req, res) => {
  const projects = await Project.find({ userId: req.user._id });
  res.send(projects);
});

router.post("/projects", async (req, res) => {
  const {
    projectName,
    projectBudget,
    projectDuration,
    industry,
    companyName,
    numberOfEmployees,
    diamond,
  } = req.body;

  if (
    !projectName ||
    !projectBudget ||
    !projectDuration ||
    !industry ||
    !companyName ||
    !numberOfEmployees ||
    !diamond
  ) {
    return res.status(422).send({ error: "Must provide all project details" });
  }

  try {
    const project = new Project({
      projectName,
      projectBudget,
      projectDuration,
      industry,
      companyName,
      numberOfEmployees,
      diamond,
      userId: req.user._id,
    });

    await project.save();

    //res.send(project);
  } catch (err) {
    res.status(422).send({ error: err.message });
  }
  try {
    const rec = await Recommendation.find({ diamond });
    //console.log(diamond);
    console.log(description);
    res.send(rec);
  } catch (err1) {
    res.status(422).send({ error: err1.message });
  }
});

module.exports = router;

Using postman, in the projectRoutes.js file, when I try to send the post request on localhost:3000/projects, I am trying to create a new project and in response I want description. My logic is that, after I save the new project in projects collection, I am trying to find the document with the SAME DIAMOND OBJECT criteria in recommendations collection which is also present in projects collection. Meaning, I have pre-defined records in recommendations collection and projects collection::

recommendations collection

projects collection

So I need some way so that when I try to add a new project for a user, the criteria object in diamond array I set matches to the criteria object in diamond array in pre-defined one of recommendations documents and in the post request localhost:3000/projects I can return description in response. As I'm doing console.log(description) in projectRoutes.js, it's showing as undefined. I don't know why. Hope it makes sense.

Basically, the idea is there will be limited number of recommendations with unique criterias. So whenever a new project is created based on the criteria, a recommendation is displayed to the user.

Upvotes: 0

Views: 38

Answers (1)

thammada.ts
thammada.ts

Reputation: 5245

Assuming you have only one array element in a project and in an a recommendation

const {
  projectName,
  projectBudget,
  projectDuration,
  industry,
  companyName,
  numberOfEmployees,
  diamond,
} = req.body;

const [projectDiamond] = diamond // get the first object in the diamond array
const { criteria } = projectDiamond // extract criteria

const recommendation = await Recommendation.find({ 'diamond.criteria': criteria });

Please note that the order of criteria fields must match, since we are looking up a matching object in an array.

Reference: https://docs.mongodb.com/manual/tutorial/query-arrays/#query-an-array

Upvotes: 1

Related Questions