Today we will look about how to build up a relation with mongoose and dig deep into its important functions such as populate(), search() and also I’m going to discuss about authentication briefly.






Let’s Create a User Model

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

const userSchema = new Schema({
  name: {
    type: String,
    required: true,
  },

  email: {
    type: String,
    required: true,
  },
  cart: {
    items: [
      {
        productId: { type: Schema.Types.ObjectId ,ref: "Product" },
      //ref defines the relation     (with Product collection) 
        quantity: { type: Number, required: true },
      },
    ],
  },
});

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



in App.js


mongoose
  .connect("mongodb://localhost:27017/nodefirst", {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  })
  .then(() => {
    User.findOne().then((user) => {
      if (!user) {
        const user = new User({ //New user Hard-coded just for now
          name: "Yasas",
          email: "yasassandeepa@gmail.com",
          cart: { items: [] },
        });
        user.save();
      }
    });

    app.listen(3000);
    console.log("Server running at http://127.0.0.1:3000/");
  })
  .catch((err) => {
    console.log(err);
  });


In App.js => before all middleware’s

app.use((req, res, next) => {
  User.findById("5eb761eb25c47749443eca0c")//user id that created prev
    .then((user) => {
      console.log(user);
      req.user = user;

      next();
    })
    .catch((err) => {
      console.log(err);
    });
});



Setting References - Relations

In Products model we add a new field to reference the user.

userId:{
    type: Schema.Types.ObjectId,
    ref:'User'   //refer the user Model
  },

then when adding the product -> we can pass his id (or complete user)




product controller

exports.postAddProduct = (req, res, next) => {
  const title = req.body.title;
  const imgUrl = req.body.imgUrl;
  const price = req.body.price;
  const description = req.body.description;

  const product = new Product({
    title: title,
    price: price,
    description: description,
    imgUrl: imgUrl,
    userId: req.user, 
//here we adding the user (but mongoose automatically take user id)
  });
  product
    .save()
    .then((result) => {
      console.log(result);

      res.redirect("/");
    })
    .catch((err) => {});
};

Mongoose Special -> Populate()

This will generate user data with relevant to user Id in one request.
Populate() will automatically fetch relevant id data.

exports.getProducts = (req, res, next) => {
  Product.find()
    .populate("userId")
    .then((products) => {
   
      console.log(products);
/*{ _id: 5eb764ebd29acc214436f815,
    title: 'New Prod',
    price: 65,
    description: 'Des 1',
    imgUrl: 'ssdsd',
    userId:  //not returning the id but returning the relevant data also  //very IMP
     { cart: [Object],
       _id: 5eb763325e918a55dca33e11,
       name: 'Yasas',
       email: 'yasassandeepa@gmail.com',
       __v: 0 },
    __v: 0 }*/
   
    })
    .catch((err) => {});
};

.select()
we can select what are the fields we want by

exports.getProducts = (req, res, next) => {
  Product.find()
    .select("title price -_id") //minus sign for excludes
    .populate("userId","name")
    .then((products) => {
     
      console.log(products);
/*
[ { title: 'New Prod',
    price: 65,
    userId: { _id: 5eb763325e918a55dca33e11, name: 'Yasas' } } ]
*/
   
    })
    .catch((err) => {});
};


Authorization -> lock down the access

Fetching data relevant to the user.

exports.getAdminProducts = async (req, res, next) => {
  Product.find({ userId: req.user._id })
    .then((products) => {
      res.render("admin/products", {
        prods: products,
        pageTitle: "Admin Product List",
        hasProducts: products.length > 0,
        active: "adminProducts",
      });
    })
    .catch((err) => {
      console.log(err);
    });
};


When Editing a product

if(product.userId.toString() !== req.user._id){
    res.redirect('/');
}

when Deleting a product

exports.postDeleteProduct = (req, res, next) => {
  const prodId = req.body.productId;

  Product.deleteOne({_id:prodId,userId:req.user._id})
// lets match it for the both userid and product id
    .then(() => {
      return res.redirect("/admin/products");
    })

    .catch((err) => {});
};