Mongoose .populate() - node.js

I am a beginner.
I have two mongoose schema, orders and customers.
orders schema
const mongoose = require("mongoose");
const orderSchema = new mongoose.Schema({
customer: {type: mongoose.Schema.Types.ObjectId, ref: "Customer"}
});
module.exports = mongoose.model("Order", orderSchema);
customers schema
const mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
const customerSchema = new mongoose.Schema({
name: String,
email: String
username: String,
password: String
});
customerSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("Customer", customerSchema);
This is my code when I insert new order
const Orders = require("../models/orders");
Orders.create({customer: req.user});
I want to console.log() all the orders and customers by using .populate()
Here is my code
Orders.find({}).populate("customers").exec((err, order) => {
if(err) {
console.log(err);
} else {
console.log(order);
}
});
I want to get the customer's id, name, and email but the problem is I only get the customer's id

Orders.find({}).populate("customer").exec((err, order) => {
if(err) {
console.log(err);
} else {
console.log(order);
}
})
or you can try
Orders.find({}).populate({path:"customer"}).exec((err, order) => {
if(err) {
console.log(err);
} else {
console.log(order);
}
})

Related

mongodb one to many relationship using nodejs and express

Its been a tough time for me trying to figure this out.
The problem I'm trying to solve is this:
I have USERS who has list of COMPANIES,
this COMPNAY has list of PROJECTS etc.
I'm trying to create a PROJECT under a COMPANY and a COMPANY under a USER using referencing.
This USER is going to be populated from form fields likewise COMPANY PROJECT
USERS SCHEMA
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
//============= User Schema============//
const userSchema = new Schema({
name: String,
email: String,
//referencing user's company/companies
company: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'company',
},
],
},{
timestamps: true
});
const Users = mongoose.model('user', userSchema);
module.exports = Users;
COMPANY SCHEMA
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
//======== Company schema ========//
const compSchema = new Schema({
company_name: String,
//referencing user schema
user: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
],
//referencing projects
projects: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'project',
},
],
},{
timestamps: true
});
const Company = mongoose.model('company', compSchema);
module.exports = Company;
PROJECT SCHEMA
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
//PROJECT SCHEMA
const projectSchema = new Schema({
project_title: String,
//referencing company schema
company: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'company',
}
],
},{
timestamps: true
});
const Projects = mongoose.model('project', projectSchema);
module.exports = Projects;
CONTROLLERS
const Users = require('./userSchema');
const Company = require('./companySchema');
const Projects = require('./projectSchema');
//create user
exports.createUser = async (req, res) => {
const data = {
name: req.body.name,
email: req.body.email,
}
Users.create(data, (err, done) => {
if(err) return err;
res.json({UserData: done});
return;
});
}
exports.getAllUsers = async(req, res) => {
}
//create company
exports.createCompany = async (req, res) => {
const CompanyData = {
company_name: req.body.company_name,
}
Company.create(companyData, (err, done) => {
if(err) return err;
res.json({CompanyDetails: done});
return;
});
}
exports.getllCompany = async (req, res) => {
}
//create project
exports.createProject = async (req, res) => {
const projectData = {
project_title: req.body.project_title,
}
Projects.create(projectData, (err, done) => {
if(err) return err;
res.json({ProjectDetails: done});
return;
});
}
exports.getAllProjects = async (req, res) => {
}
I understand that populate can be used to push documents to children. Any assistance offered will be highly appreciated
Store reference
Firstly, while creating a Company inside createCompany controller, you should add user _id in users array like this:
const CompanyData = {
company_name: req.body.company_name,
users: [req.body.userId] // Lets assume, user _id is coming in request body
}
Company.create(companyData, (err, done) => {
// Your code
});
Then, when you create a Project, add _id of Company you just created, in createProject controller like this:
const projectData = {
project_title: req.body.project_title,
company: [req.body.comapnyId] // Again assuming, company _id is coming in request body
}
Projects.create(projectData, (err, done) => {
// Your code
});
Update reference
Also, as I see in your schemas, you are trying to keep it bidirectional, like user's _ids in company doc & company's _ids in user doc.
To achieve this, if you create a user, you should update the corresponding company with pushing(addToSet actually) new user _id in user array.
Example:
To create a user in controller, run two scripts synchronously one-by-one:
Create a user with company _id and other details.
const data = {
name: req.body.name,
email: req.body.email,
company: [req.body.companyId]
}
Users.create(data, (err, done) => {
// Your code
});
Update company doc(whose _id is saved in above user) with _id of newly created user.
const updateCompany = { "$addToSet": { user: user._id } }; // Get `user._id` from above synchronous script
Company.update({_id: req.body.companyId}, data, (err, done) => { // Updated filter
// Your code
});

mongoose.Schema.Types.ObjectId is giving an empty array when console.logged

This is my table schema
var mongoose=require("mongoose");
var tableSchema=new mongoose.Schema({
tName:String,
keys:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"key"
}
],
fields:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"field"
}
]
})
module.exports=mongoose.model("table",tableSchema);
----Key Schema
var mongoose=require("mongoose")
var keySchema=new mongoose.Schema({
name:[String],
value:[String]
})
module.exports=mongoose.model("key",keySchema);
---field Schema
var mongoose=require("mongoose")
var fieldSchema=new mongoose.Schema({
name:[String],
value:[String]
})
module.exports=mongoose.model("field",fieldSchema);
----How I Pushed into
app.post("/table/:id/value",function(req,res){
var Key={
name:req.body.key,
value:req.body.keyValue
}
var Field={
name:req.body.field,
value:req.body.fieldValue
}
table.findById(req.params.id,function(err,foundTable){
if(err){
console.log(err)
}
else{
console.log(foundTable)
key.create(Key,function(err,createKey){
foundTable.keys.push(createKey)
console.log(createKey)
})
field.create(Field,function(err,createField){
foundTable.fields.push(createField)
console.log(createField)
})
foundTable.save();
console.log(foundTable);
res.redirect("/table/"+req.params.id)
}
})
})
ObjectId are not being refernced
Here is the Image that prints the table
How I populated the table
app.get("/table/:id",function(req,res){
table.findById(req.params.id).populate("keys").populate("fields").exec(function(err,foundTable){
if(err){
console.log(err)
res.redirect("/")
}
else{
console.log(foundTable);
res.render("show",{table:foundTable})
}
})
})
I Dont know where I had gone wrong,
everything seems to be fine but
the objected is not referenced when printed and
it is not being populated
How it should be printed reference: https://bezkoder.com/mongoose-one-to-one-relationship-example/
This is an example:
1st schema
const mongoose = require("mongoose");
const Customer = mongoose.model(
"Customer",
new mongoose.Schema({
name: String,
age: Number,
gender: String
})
);
module.exports = Customer;
2nd schema
const mongoose = require("mongoose");
const Identifier = mongoose.model(
"Identifier",
new mongoose.Schema({
cardCode: String,
customer: {
type: mongoose.Schema.Types.ObjectId,
ref: "Customer"
}
})
);
module.exports = Identifier;
How it should be printed
{
_id : ObjectId("5da000be062dc522eccaedeb"),
cardCode : "5DA000BC06",
customer : ObjectId("5da000bc062dc522eccaedea"),
__v : 0
}
How it should be populated
[ { _id: 5da135bf61a1dd3e9c2a6e82,
cardCode: '5DA135BD61',
customer:
{ _id: 5da135bd61a1dd3e9c2a6e81,
name: 'bezkoder',
age: 29,
gender: 'male',
__v: 0 },
__v: 0 } ]
try this .populate([ 'keys', 'fields' ])
The reason why keys and fields are not inserted is that the foundTable.save() will be executed before creating the new Key and Field documents and push there _id to the foundTable.
One way to solve the issue is by using async/await. You can modify your code as below using async/await
app.post("/table/:id/value", async function (req, res) {
var Key = {
name: req.body.key,
value: req.body.keyValue,
};
var Field = {
name: req.body.field,
value: req.body.fieldValue,
};
try {
const foundTable = table.findById(req.params.id);
const createKey = await key.create(Key);
const createField = await field.create(Field);
foundTable.keys.push(createKey._id);
foundTable.fields.push(createField._id);
await await foundTable.save();
res.redirect("/table/"+req.params.id)
} catch (err) {
console.log(err);
// handle failure here
}
});
This will make sure the Key and Field are created and _id is pushed to foundTable before saving the foundTable
Regarding the populate query. Looks like once you save the _id of Field and Key in foundTable your existing query itself should work

Cascade Delete in mongo

I am new to MongoDB. I created 4 collections & they are connected with each other. (I am using node.js to write it)
Here, it's my question. How can I delete all records at once? Is there something like deep level population?
This one holds all models.
const DataModel = mongoose.Schema({
_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', require: true},
order: { type: mongoose.Schema.Types.ObjectId, ref: 'Order', require: true},
});
User model
const userSchema = mongoose.Schema({//other stuff});
Order model
const orderSchema = mongoose.Schema({
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
//other stuff
});
Product model
const productSchema = mongoose.Schema({//other stuff});
I can delete the entry with these code from the database, but the other entries still there
exports.delete_data = (req, res, next) => {
const id = req.params.userId;
userDataModel.deleteOne({_id: id})
.exec()
.then(docs => {
res.status(200).json({
message: 'Record Deleted',
request: {
type: 'POST'
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
Update: However, I wonder, Could I call other defined delete functions for order, product inside delete_data
As #Geert-Jan suggest, cascade delete is my solution. The link that geert-jan gave solve my problem. However, I wonder, Could I call other defined delete functions for order, product inside delete_data
i did this and it could be good for someone who wants to delete documents in cascade linked to any field of a model.
async blackHole() {
try {
const rtn = new ApiResponse<any>();
const userId = id;
const accountId = mongoose.Types.ObjectId(id);
var CollectionNames: any[] = [];
mongoose.connection.db.listCollections().toArray(function (err, collections) {
CollectionNames = collections.map(c => c.name);
CollectionNames.forEach((element: any) => {
mongoose.connection.db.collection(element).deleteMany({ "account": accountId });
});
});
const accountController = new AccountController(this.wsParams);
await accountController.delete(id)
await super.delete(userId);
return rtn;
} catch (error: any) {
const rtn = new ApiResponse<any>();
rtn.message = error;
rtn.success = false;
rtn.status = 422;
return rtn;
}
}
I hope you can use it :D

How do you save to three collections at once?

I'm building my first mean stack app. It's a review site that contains three models: User, Review, and Company.
When I make a review, I want the new review to be saved to the 'review' collection, and for that review to be connected by reference to the company being reviewed and the user who wrote the review. I also want the user to hold a reference to the review, and the company to hold a reference to all the reviews it has. Here are my models:
Review
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const reviewSchema = new Schema ({
companyName: String,
companyId: { type: Schema.Types.ObjectId, ref: 'Company'},
starRating: Number,
subject: String,
commentBody: String,
createdBy: { type: Schema.Types.ObjectId, ref: 'User'},
});
const Review = mongoose.model("Review", reviewSchema);
module.exports = Review;
Company
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const companySchema = new Schema ({
companyName: String,
about: String,
basedIn: String,
materialOrigins: [String],
productRange: [String],
category: String,
reviews: [ {type: Schema.Types.ObjectId, ref: 'Review'} ],
socialRating: Number,
environmentalRating: Number,
priceRange: Number
});
const Company = mongoose.model("Company", companySchema);
module.exports = Company;
User
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema ({
email: String,
firstName: String,
lastName: String,
password: String,
image: Object,
aboutText: String,
reviews: [ { type: Schema.Types.ObjectId, ref: "Review" } ]
// comments: { type: Schema.Types.ObjectId, ref: 'Comment' }
});
const User = mongoose.model("User", userSchema);
module.exports = User;
This is my current route, which currently saves the review to the collection and attaches the user. However, the user doesn't get the review.
route
router.post('/:category/:company', (req, res) => {
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var userId = req.body.userId;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
userId
});
User.findById(userId, {
}, (err, user) => {
if (err) {
return res.send(err);
} else {
console.log("checking out user in route", user);
user.reviews.push(newReview);
user.save();
newReview.save((err, review) => {
if (err) {
return res.status(400).json({ message: err });
} else {
res.status(200).json({ message: 'Review saved', review });
}
});
}
});
I haven't tried adding the company in because I'm trying to do one thing at a time. I've been looking at 'populate', but all of the documentation seems to only use two models at once. Is it possible to do three at once? Or am I overcomplicating this?
Apologies if this is all overcomplicated. I'm fairly new to MongoDB and MEAN stack in general. Thanks for your help.
Ok, I did it, for any people landing on this page wondering the same thing in the future.
Here's my route:
router.post('/:category/:company', (req, res, next) => {
var companyName;
var companyId;
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var createdBy = req.body.createdBy;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
createdBy
});
//I need the companyId and companyInfo for later use in my review save. I'm calling the company with the name I have from my params, and setting the id and name with the received data from Mongo.
Company.findOne({"companyName": req.params.company}, (err, company) => {
if (err) {
return res.status(400).json({ message: err });
} else {
this.companyName = company.companyName;
this.companyId = company.id;
}
});
newReview.save((err, review) => {
//Push the review id to the user
if (err) {
return res.status(400).json({ message: err });
} else { User.findByIdAndUpdate({_id: createdBy },{$push: {reviews: review.id} }, (err) => {
if (err) {
console.log("There was an error pushing review to user");
next(err);
//Push the review id to the company
} else { Company.findOneAndUpdate({ "companyName": req.params.company}, {$push: {reviews: review.id}}, (err, company) => {
if (err) {
console.log("There was an error pushing review to company");
next(err);
} else {
//Updates the review by setting companyId and companyName properties to review for Mongo
Review.update({_id: review.id}, {$set: {companyId: this.companyId, companyName: this.companyName}}, (err, changes) => {
if(err) {
return res.status(400).json({message : err});
} else {
console.log("updating review successfully with company info", changes);
}
});
console.log ("Review successfully saved");
res.json({
review: review,
});
}
});
}
});
}
});
});
If anyone has feedback on how this could be done better/more efficiently, let me know. Cheers.

Mongoose, can't print products from database

I have problem with print items in console.log or res.json from database.
what am I doing wrong
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test');
var Schema = mongoose.Schema;
var productSchema = new Schema({
title: String,
price: Number
});
var product = mongoose.model('product, productSchema');
mongoose.connect(db);
var db = 'mongodb://localhost/product';
router.get('/books', function(req, res) {
console.log('getting all products');
product.find({})
.exec(function(err, product) {
if (err) {
res.send('errror');
} else {
console.log(product);
res.json(product);
}
})
});
name of database products is : db.product
Thanks
Error:
C:\Users\Turqus\Desktop\node\products\node_modules\mongoose\lib\index.js:382
throw new mongoose.Error.MissingSchemaError(name);
^
MongooseError: Schema hasn't been registered for model "product, productSchema".
Use mongoose.model(name, schema)
at Mongoose.model (C:\Users\Turqus\Desktop\node\products\node_modules\mongoose\lib\index.js:382:13)
You have to make the Database Connection first.
change this
var product = mongoose.model('product, productSchema');
to
var product = mongoose.model('product', productSchema);
mongoose.model() accepts two parameter the name of the collection your model is for and the 2nd the Schema
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test');
var Schema = mongoose.Schema;
var productSchema = new Schema({
title: String,
price: Number
});
var product = mongoose.model('product', 'productSchema');
router.get('/books', function(req, res) {
console.log('getting all products');
product.find({})
.exec(function(err, product) {
if (err) {
res.send('errror');
} else {
console.log(product);
res.json(product);
}
})
});

Resources