populate method in mongoose (node js) - javascript

I m trying to use populate( ) in node js.
Well I m trying to access, objectId of one collection into another collection.
for eg., i have collections called Project and events,
where i have schema like this.
Project schema:
const projectSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
projectName: {
type: String,
required: true,
unique: true
},
dimensions: {
type: [],
required: false
},
events: {
[type: mongoose.Schema.Types.ObjectId],
ref: 'EnrichedEvent'
},
});
module.exports = mongoose.model('Project', projectSchema);
Events Schema:
const enrichedEventSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
projectId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Project',
required: true
},
name: {
type: String,
required: true
},
type: {
type: String,
enum: ["Enriched"],
required: true
},
source: {
type: String,
required: true
},
});
and the routing code for projects to :
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const Project = require("../models/project");
router.get("/", (req, res, next) => {
Project.find()
.populate('source', 'EnrichedEvents') //When i use this populate method, I m not able to GET any events on to browser..
.exec()
.then(docs => {
const response = {
count: docs.length,
projects: docs.map(doc => {
return {
projectName: doc.projectName,
dimensions: doc.dimensions,
events: doc.events,
_id: doc._id
};
})
};
res.status(200).json(response);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
router.post("/", (req, res, next) => {
const project = new Project({
_id: new mongoose.Types.ObjectId(),
projectName: req.body.projectName,
events: req.body.events
});
project
.save()
.then(result => {
console.log(result);
res.status(201).json({
message: "Created project successfully",
createdProject: {
projectName: result.projectName,
_id: result._id,
events: result.events,
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
module.exports = router;
my problem is I can't auto populate the enriched eventsId in projects page.
for eg. Whenever i update events they should appear in projects page.but its not happening. In events page also i am not getting corresponding projectId. please point me in right direction.

Populate method takes FIELD_TO_POPULATE and FIELDS_TO_RETURN_FROM_POPULATED_DOC and you are passing it the reversed way. Also in your project schema you have used events for EnrichedEvent, so while populating use events not EnrichedEvent;
Try the following:
From:
.populate('source', 'EnrichedEvents')
TO:
.populate('events', 'EnrichedEvent')
Edit:
update your schema for EnrichedEvent:
events: [{
mongoose.Schema.Types.ObjectId,
ref: 'EnrichedEvent'
}]
It should work now.

I tried to use a similar .populate('...', '...') method but unsuccessfully. I would use
.populate('source').populate('EnrichedEvent')
or ('EnrichedEvents') depending on what you have defined in your schema.

Related

mongoDB collection creation

i have a problem with adding a collection into my database in mongodb atlas.
I have managed to import this collection before but i accidentally deleted it and now i can't upload it again. there is no error in my terminal. There for i don't know what is wrong with my code.. (image of my code and terminal are attached below)
There is anyone who might know why is this can happen?
EDIT
I tried to open a new database and my all the collections was imported to it and once again, only the product collection doesn't
//////////////////////////////////
/* require('dotenv').config({ path: '/.env' }) */
const path = require('path')
require('dotenv').config({ path: path.resolve(__dirname, '..', '.env') })
console.dir(process.env.MONGO_URI)
const mongoose = require('mongoose')
const connectDB = async () => {
try {
mongoose.connect(process.env.MONGO_URI, {
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
})
console.log('MongoDB connection SUCCESS')
} catch (error) {
console.error('MongoDB connection FAIL')
process.exit(1)
}
}
console.dir(process.env.MONGO_URI)
module.exports = connectDB
////////////////////////////////////////////////////////////////
require('dotenv').config()
const productsData = require('./data/products')
const connectDB = require('./config/db')
const Product = require('./models/product')
connectDB()
const importData = async () => {
try {
/* Product.deleteMany({}) */
Product.insertMany(productsData)
console.dir('Data Imported Successfuly')
process.exit()
} catch (error) {
console.log(error)
console.error('Error Ocured In Imported Data Process', error)
process.exit(1)
}
}
importData()
my model schema
const mongoose = require('mongoose')
const products = require('../data/products')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
countInStock: {
type: Number,
required: true,
},
imageUrl: {
type: String,
required: true,
},
})
module.exports = mongoose.model('Products', productSchema)
my code and terminal image
Product.insertMany(productsData) returns a promise, but you aren't waiting for that promise to finish before exiting the process. Add an await before it and you should be okay.
Try this to create your schema instead
const { Schema } = mongoose;
const productSchema = new Schema({
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
countInStock: {
type: Number,
required: true,
},
imageUrl: {
type: String,
required: true,
},
})
const Product = mongoose.model("Product", productSchema);
Product.createCollection();

Why won't my model save using mongoose and mongodb?

I have a simple Post model and a route to create posts at. When I create one using postman, it loads for a bit and then I get the error json back. A model is never saved.
here is the model:
const PostSchema = mongoose.Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
},
data: {
type: Date,
default: Date.now
}
});
here is the route:
router.post('/', (req, res) => {
console.log(req.body.title);
console.log(req.body.body);
const post = new Post({
title: req.body.title,
body: req.body.body
});
post.save()
.then(data => {
console.log(data);
res.json(post);
})
.catch(err => {
res.json({
error: err
});
});
});
Everything needed is imported. Please help!
Try using a try{}catch{} like this let me know if there is still an error
router.post("/", (req, res) => {
try {
const post = new Post({
title: req.body.title,
body: req.body.body,
});
post.save();
res.status(200).send(`Post created!`);
} catch (err) {
res.status(400).send({ message: err });
}
});
Also check your model is being exported
const PostSchema = mongoose.Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
},
data: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model("Post", PostSchema);

What is the proper way of mongoose populate?

Hello im new to nodejs and mongoose, i need help in mongoose populate, please help me to understand. Thanks in Advance!
here is my schema's
PropertySchema.js
const mongoose = require('mongoose')
const { Schema } = mongoose
require('./MemberSchema')
const propertySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
pname: String,
ptype: String,
price: Number,
owner: { type: mongoose.Schema.Types.ObjectId, ref: 'Members' }
})
const Props = mongoose.model('Property', propertySchema)
module.exports = Property
MemberSchema.js
const mongoose = require('mongoose')
const { Schema } = mongoose
require('./PropertySchema')
const memberSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
fname: String,
lname: String,
dob: Number,
email: String,
address: String,
phone: Number,
memtype: String,
username: {type: String, required: true},
password: {type: String, required:true},
properties: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Property' }]
})
const Members = mongoose.model('Members', memberSchema)
module.exports = Members
addPropertyRoutes.js
router.post('/add', isAuthenticated, (req, res, next) => {
const props = new Property({
_id: new mongoose.Types.ObjectId(),
pname: req.body.pname,
ptype: req.body.ptype,
price: req.body.price,
owner: new mongoose.Types.ObjectId()
})
props.save( (err, props) => {
if (err) {
console.log('Unable to register your data: ' + err)
throw err
}
console.log('Property Added Successful!')
res.redirect('/property/add')
})
})
Im using mongoose 3.6 and expressjs.
When i check my Robo 3t after adding properties it shows like this check this screenshot:
In your, property schema you have to store ownerId, not to generate new ObjectId.
The proper way to do Populate in mongoose, you can find it here.
i think the solution is this:
change your addPropertyRoutes into this :)
router.post('/add', isAuthenticated, (req, res, next) => {
const member = req.user
Members.findOne({})
const props = new Property({
pname: req.body.pname,
ptype: req.body.ptype,
price: req.body.price,
owner: member._id
})
props.save( (err, props) => {
if (err) {
console.log('Unable to register your data: ' + err)
throw err
}
console.log('Registration Successful!')
res.redirect('/property/add')
})
})
Your Welcome from noobs

node js get doesnt get anything

So I'm currently learning how to build a Rest API with Node Js and MongoDB, so naturally I've been following some tutorials, and when the time came, I've setup an example but it doesn't work.
I have 2 main files, app.js and historic.js (model).
On app.js I have the following:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
app.use(bodyParser.json());
Historic =require('./models/historic');
// Connect to Mongoose
mongoose.connect('mongodb://localhost/test', { useMongoClient: true });
var db = mongoose.connection;
console.log('Here');
db.on('error', function(err){
if(err){
console.log(err);
throw err;
}
});
db.once('open', function callback () {
console.log('Mongo db connected successfully');
});
app.get('/', (req, res) => {
res.send('Please use /api/historic');
});
app.get('/api/historics', (req, res) => {
Historic.getHistorics((err, historic) => {
if(err){
throw err;
}
res.json(historic);
});
});
app.listen(27017);
console.log('Running on port 27017...');
Then on my model I have the following:
const mongoose = require('mongoose');
// Historic Schema
const historicSchema = mongoose.Schema({
_id:{
type: String,
required: true
},
url:{
type: String,
required: true
},
price:{
type: String,
required: true
},
timestamp:{
type: String,
required: true
}
});
const Historic = module.exports = mongoose.model('Historic', historicSchema);
// Get Historics
module.exports.getHistorics = (callback, limit) => {
console.log('Get Historics-Historic');
Historic.find(callback).limit(limit);
console.log('Get Historics-Historic-After find');
console.log(limit);
}
Whenever I try to access http://localhost:27017/api/historics/ I only get: [].
I know that I have data on my DB as you can see on the image:
data on DB test
Any tips?
According to Docs http://mongoosejs.com/docs/2.7.x/docs/finding-documents.html the callback should be at least the 2nd parameter of the .find method.
Try to replace
// Get Historics
module.exports.getHistorics = (callback, limit) => {
console.log('Get Historics-Historic');
Historic.find(callback).limit(limit);
console.log('Get Historics-Historic-After find');
console.log(limit);
}
to
// Get Historics
module.exports.getHistorics = (callback, limit) => {
var query = Historic.find({});
query.limit(limit);
query.exec(callback);
}
I've been told the solution and it works.
Old Code:
const historicSchema = mongoose.Schema({
_id:{
type: String,
required: true
},
url:{
type: String,
required: true
},
price:{
type: String,
required: true
},
timestamp:{
type: String,
required: true
}
});
Solution:
const historicSchema = mongoose.Schema({
_id:{
type: String,
required: true
},
url:{
type: String,
required: true
},
price:{
type: String,
required: true
},
timestamp:{
type: String,
required: true
}
}, {collection: 'historic'});
I needed add the collection name that was defined on Mongoose

content is missing from HTTP Get and Post requests in Express/Mongoose project

I have the following files. I have a recipe.js file which outlines the Mongoose Schema for a recipe and the comments for a recipe. The code for it goes as follows:
const express = require('express');
const mongoose = require('mongoose');
const User = require('../models/user');
let Schema = mongoose.Schema;
let commentSchema = Schema({
rating: {
type: Number,
// required: true,
min: 1,
max: 5,
},
recipeItem: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Recipe'
},
comment: {
type: String,
// required: true
},
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
likedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
favouredBy: {
type: mongoose.Schema.Types.ObjectId
}
});
let Comment = mongoose.model('Comment', commentSchema);
let recipeSchema = Schema({
name: {
type: String,
required: true
},
description: {
type: String,
},
steps: {
type: String,
required: true,
},
ingredients: {
type: Array,
required: true
},
comments: [commentSchema],
category: {
type: String,
required: true,
},
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
/// So I learnt that by defining the string as "Recipe" in the model function, I will have to lower case it
/// and pluralize it when I use it with res.json and other such things (i.e. "Recipe" => recipes).
let Recipe = mongoose.model('Recipe', recipeSchema);
module.exports = Recipe;
module.exports = Comment;
/// refactor this so that these are in the router, not in the models file
/*
module.exports.getRecipeByName = (name, callback) => {
let nameQuery = {name: name};
Recipe.findOne(nameQuery, callback);
};
module.exports.getRecipesByCategory = (category, callback) => {
Recipe.find({'category': category});
};
*/
I also have a user.js file where I outline a a User model and the relation it has to the other models/schemas. The code in the file is as follows:
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const passportLocalMongoose = require('passport-local-mongoose');
const passport = require('passport');
let Schema = mongoose.Schema;
let User = Schema({
name: {
type: String
},
// The passport plugin already inputs username and password into our Schema
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true,
},
profilePic: {
type: String
},
email: {
type: String,
unique: true,
required: true
},
admin: {
type: Boolean,
defualt: false
},
usersRecipes: [{type: Schema.Types.ObjectId, ref:'Recipe'}],
userComments: [{type: Schema.Types.ObjectId, ref: 'Comment'}],
usersFavouriteRecipes: [{type: Schema.Types.ObjectId, ref: 'Recipe'}],
usersLikedRecipes: [{type: Schema.Types.ObjectId, ref: 'Recipe'}]
});
let options = ({missingPasswordError: "Incorrect password, try again"});
User.plugin(passportLocalMongoose, options);
module.exports = mongoose.model('User', User);
And here is recipeRouter.js, the file where I define all the HTTP requests and routes:
const express = require('express');
const passport = require('passport');
const Recipe = require('../models/recipe');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const verification = require('../verification');
const Comment = require('../models/recipe');
// I temporarily removed verification.checkIfUserExists to see if all this database stuff works
router = express.Router();
router.use(bodyParser.json());
router.get('/', (req, res) => {
res.json('Here are the recipes!')
});
router.get('/showrecipes', (req, res) => {
Recipe.find({}).populate('Comment').exec((err, recipes) => {
if (err) throw err;
res.json(recipes);
})
});
router.get("/showrecipes/:recipeId", (req, res) => {
let nameQuery = {_id: req.params.recipeId};
Recipe.findOne(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
})
//// Don't know if this is correct
.populate('comment.recipeItem');
});
router.get('/showrecipes/category/:categoryname', (req, res) => {
let nameQuery = {category: req.params.categoryname};
Recipe.find(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
router.post('/addrecipe', (req, res, next) => {
Recipe.create({
name: req.body.name,
description: req.body.description,
steps: req.body.steps,
ingredients: req.body.ingredients,
category: req.body.category
}, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
// See if this works
router.put("/showrecipes/:recipeId", (req, res) => {
let query = {_id: req.params.recipeId};
Recipe.findByIdAndUpdate(query, {
$set: req.body
}, {
new: true
}, (err, recipe) => {
if (err) throw err;
res.json(recipe)
})
});
router.delete("/showrecipes/:recipeId", (req, res) => {
let query = {_id: req.params.recipeId};
Recipe.findByIdAndRemove(query, (err, recipe) => {
if (err) throw err;
res.send('Recipe was succesfully deleted');
})
});
router.get("/showrecipes/:recipeId", (req, res) => {
let nameQuery = {_id: req.params.recipeId};
Recipe.findOne(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
})
.populate('comments')
.exec((err) => {
if (err) throw err;
})
});
router.post("/showrecipes:/:recipeId/addcomment", (req, res, next) => {
Comment.create({
rating: req.body.rating,
comment: req.body.comment,
postedBy: postedBy,
date: Date.now(),
recipeItem: recipeId
})
});
router.get('/showrecipes/byuser/:username', (req, res) => {
let query = {postedBy: req.params.username};
Recipe.find(query, (err, recipes) => {
if (err) throw err;
res.json(recipes)
})
});
module.exports = router;
Now, at some point I was able to create recipes and store them in my database without a problem. But now this weird thing happens.
Here, I make my post request as you can see in the screenshot below:
But for some strange reason, everytime I make a get request, none of the key/value pairs I specified in my json body request are there. Each recipe object now only as the _id in it.
Can anyone help me? This just seems so weird.
Looks like you're simply missing the application/json Content-Type header.
In Postman, just set the header, as shown in this gif.

Categories