how can i access mongodb document's array? (mongodb, nodejs) - node.js

Hi i have some problems with mongodb.
const mongoose = require('mongoose');
const companySchema = new mongoose.Schema({
name: String,
url: String,
images: Array
});
const categoriesSchema = new mongoose.Schema({
company: companySchema,
name: String
});
module.exports = mongoose.model('categories', categoriesSchema);
above of code is model
app.post('/addCompanyinfo', function (req, res){
var news = new Categories();
news.company[name]= req.body.company; <--- here!
news.save(function (err) {
if(err) {
console.error(err);
res.json({result: 0});
return;
}
res.json({result: 1})
})
})
and this is router code. and i want to access
categoriesSchema-> company (companySchema)-> name.
how can i access company schema's 'name' ??
your help will be a big lucky in future to you :)

You need to create an Object for Company to assign its properties
var news = new Categories();
var company = new Company();
news.company = company;
news.name = 'test category'
company.name = 'test company';
console.log(company);
console log
{ name: 'test category',
company: { _id: 5a61629b74f8df0bd73142ba, images: [] },
_id: 5a61629b74f8df0bd73142b9 }
{ name: 'test company', _id: 5a61629b74f8df0bd73142ba, images: [] }

You can post your data in json format and use bodyParser.json() middleware in your app.js, and your backend code can be this:
router.post('/', function(req, res, next) {
var news = new Categories(req.body); // create record directly with the json data
console.log(req.body.company.name); //just access it directly
news.save(function (err) {
if(err) {
console.error(err);
res.json({result: 0});
return;
}
res.json({result: 1});
});
});
and json format can be this:
{
"company": {
"name": "test company name",
"url": "http://test.com",
"image": []
},
"name": "test name"
}

Related

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.

Need to do a many comments belong to one article relation MongoDB

I am using Mongoose/MongoDB and I am trying to associate many comments to one article. My app begins by scraping from a website and then the user has the option to save each article that was scraped into the MongoDB. When the user chooses to save one article, I save it into database. So when a user clicks on one of their saved articles, they can comment on them. Each article has its own comment section I need to retrieve the correct comments.
//My post comment request in JS file
function postComment(){
var articleComment = {
comment: $('#comment').val().trim()
}
$.post('/comments/' + articleID, articleComment).done(function(data){
$('.main-popup').fadeOut();
console.log('DONNE', data);
});
}
//Post route in controller
router.post('/comments/:id', function(req, res){
var newComment = new Comment(req.body);
newComment.save(function(err, doc){
if(err){
console.log(err);
}else{
Comment.findOneAndUpdate({ "_id": doc._id }, { "article": req.params.id }).exec(function(err, doc){
if(err){
console.log(err);
res.send(err);
}else{
res.send(doc);
}
});
}
});
});
//Get request to get correct comments when clicked on specific article
function showCommentBox(){
$('.comments').empty();
$('#comment').val("");
articleID = $(this).attr('data-article-id');
$.get('/comments/' + articleID, function(data){
if(data.article){ //This is undefined*********************
for(var x = 0; x < data.comment.length; x++){
$('.comments').append("<div><h2>" + data.comment[x].comment + "</h2><span><button>×</button></span></div>");
}
}
$('.main-popup').fadeIn();
});
}
//Get route in controller
router.get('/comments/:id', function(req, res){
Comment.findOne({ "article": req.params.id }).populate("article").exec(function(err, doc){
if(err){
console.log(err)
}else{
res.json(doc);
}
});
});
//Article Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ArticleSchema = new Schema({
title: {
type: String
},
link: {
type: String
},
description: {
type: String
},
img: {
type: String
}
});
var Article = mongoose.model("Article", ArticleSchema);
module.exports = Article;
//Comment Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CommentSchema = new Schema({
comment: {
type: String
},
article: {
type: Schema.Types.ObjectId,
ref: 'Article'
}
});
var Comment = mongoose.model('Comment', CommentSchema);
module.exports = Comment;
First, you're missing $set when you do .findOneAndUpdate. Also I think you should convert a string to Mongo ObjectId before setting it.
So it might look likt this:
const ObjectId = mongoose.Types.ObjectId;
Comment.findOneAndUpdate({ "_id": doc._id }, {$set: {"article": new ObjectId(req.params.id) }})
Also you don't need to make 2 database calls. You could article id before saving newComment and then simply send it as a response like this:
//Please notice that mongoose.Schema.Types.ObjectId and mongoose.Types.Object are different types.
//You need this one here:
const ObjectId = mongoose.Types.ObjectId;
router.post('/comments/:id', function(req, res){
var newComment = new Comment(req.body);
newComment.article = new ObjectId(req.params.id);
newComment.save(function(err, doc){
if (err) {
console.error(err);
res.send(err);
return;
}
res.send(doc);
});
});

Mongoose update is not working

My question here is why isn't the watchlistSchema.update(function (error) { { $push: { watchlist: req.body.stockAdded } }}); line updating the existing schema for the watchlist attribute? When I use this update nothing happens and it returns null. When I change it to watchlistSchema.save it work but it creates and entirely different document. I would like to basically check for the user and watchlist and if they both exist together I would like to push a string into the watchlist array. I am very new to mongoose so it is a bit confusing.
var Schema = mongoose.Schema;
var watchlistSchema = new Schema({
watchlist: [{ }],
user: String
});
var Watchlist = mongoose.model('Watchlist', watchlistSchema, "watchlist");
app.post('/watchlistPost', function (req, res) {
var watchlistSchema = Watchlist({
'watchlist': req.body.stockAdded,
'user': req.user.username
});
Watchlist.findOne({
$and: [{
'watchlist': req.body.stockAdded,
}, {
'user': req.user.username
}]
}, function (err, list) {
if (list) {
res.status(200).send({ "success": "Updated Successfully", "status": 200 });
} else {
if (req.user) {
watchlistSchema.update(function (error) {
{ $push: { watchlist: req.body.stockAdded } }
});
} else {
}
}
})
});
Your update statement needs to contain the "find" query. So it can appy the update condition to all documents matching the specified query.
change your code to something like:
var Schema = mongoose.Schema;
var watchlistSchema = new Schema({
watchlist: [{ }],
user: String
});
var Watchlist = mongoose.model('Watchlist', watchlistSchema, "watchlist");
app.post('/watchlistPost', function (req, res) {
var watchlistSchema = Watchlist({
'watchlist': req.body.stockAdded,
'user': req.user.username
});
var query = {
$and: [{
'watchlist': req.body.stockAdded,
}, {
'user': req.user.username
}]};
Watchlist.update(query, { $push: { watchlist: req.body.stockAdded } }, ==your callback to check stuff==);

'populate' and working with parent / child models in Mongoose / MongoDB

I have a pretty simple setup where I'm trying to populate my Mongoose JSON responses with all Comments that belong to a Post
I thought that calling 'populate' on Post would return all comments related to the Post, but instead I'm getting an empty array. I just don't get what I'm doing wrong.
post.js
const mongoose = require('mongoose');
const db = require('./init');
const postSchema = new mongoose.Schema({
title: String,
url: String,
body: String,
votes: Number,
_comments: [{type: mongoose.Schema.Types.ObjectId, ref: "Comment"}]
});
const Post = mongoose.model('Post', postSchema);
module.exports = Post;
comment.js
const mongoose = require('mongoose');
const db = require('./init');
const commentSchema = new mongoose.Schema({
// post_id: post_id,
_post: { type: String, ref: 'Post'},
content: String,
posted: { type: Date, default: Date.now() }
});
const Comment = mongoose.model('Comment', commentSchema);
module.exports = Comment;
posts.js
router.get('/', function(req, res, next) {
// An empty find method will return all Posts
Post.find()
.populate('_comments')
.then(posts => {
res.json(posts)
})
.catch(err => {
res.json({ message: err.message })
})
});
and within the posts.js file I've set up a route to create a comment when a post request is sent to posts/post_id/comments
commentsRouter.post('/', function(req, res, next) {
console.log(req.params.id)
//res.json({response: 'hai'})
comment = new Comment;
comment.content = req.body.content;
comment._post = req.params.id
comment.save((err) => {
if (err)
res.send(err);
res.json({comment});
});
});
Comments are being created when I post to this route, and they are created with the correct _post value, however populate isn't picking them up.
For example, this post has been created, and it doesn't populate the associated comment below:
{
"post": {
"__v": 0,
"votes": 0,
"body": "Test Body",
"url": "Test URL",
"title": "Test Title",
"_id": "587f4b0a4e8c5b2879c63a8c",
"_comments": []
}
}
{
"comment": {
"__v": 0,
"_post": "587f4b0a4e8c5b2879c63a8c",
"content": "Test Comment Content",
"_id": "587f4b6a4e8c5b2879c63a8d",
"posted": "2017-01-18T10:37:55.935Z"
}
}
When you create a comment, you also have to save the comment instance _id to a post. So within the save() callback, you can do something like
commentsRouter.post('/', function(req, res, next) {
console.log(req.params.id)
//res.json({response: 'hai'})
comment = new Comment({
content: req.body.content;
_post: req.params.id
});
comment.save((err, doc) => {
if (err)
res.send(err);
Post.findByIdAndUpdate(req.params.id,
{ $push: { _comments: doc._id } },
{ new: true },
(err, post) => {
if (err)
res.send(err);
res.json({doc});
}
)
});
});

Adding slug to req params url in express

I'm using the 'slug' npm library to give-strings-dashes-for-url-cleanliness. The library works when I console.log() a string, and it's required properly into all of the relevant controllers.
However, I can't figure out how implement slug() properly to format my URLs. The problem I'm having is that a product name might be "Foo Bar Baz Quux", but I can't seem to find the right implementation for slug() without disrupting the connection between the app.js route and the findOne query via mongoose.
app.js
app.get('/market/:product_name', marketController.getProduct);
controller.js
exports.getProduct = function(req, res, next) {
var product_name = req.params.product_name;
// var slugProduct = slug(product_name);
Product.findOne({'name': product_name}, function(err, product) {
if (err) return next(err);
return res.send(product.data);
});
}
Perhaps you could "slugify" a product by defining a slug property while setting up your "Product Schema". I can confirm it works if using mongoose with along mongoose-slug-generator plugin, see link... You could set it up as follows:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const slug = require('mongoose-slug-generator');
// * mongoose slug generator options
const options = {
separator: '-',
lang: 'en',
truncate: 120
};
// * Init mongoose slug generator plugin
mongoose.plugin(slug, options);
const ProductSchema = new Schema({
name: {
type: String,
trim: true
},
slug: {
type: String,
slug: 'name', // genarating slug from multiple properties is allowed ['name', 'brand']
unique: true
},
price: {
type: Number,
required: true
},
brand: {
type: String,
default: 'Apple'
}
});
module.exports = mongoose.model('Product', ProductSchema);
exports.getProduct = function(req, res, next) {
const { product_name } = req.params;
Product.findOne({ slug: product_name }, function(err, product) {
if (err) return next(err);
if (!product) {
return res.status(404).json({
message: 'Product data not found.'
);
}
res.status(200).send(product);
});
}
app.get('/market/:product_name', marketController.getProduct)
// request
const response = await axios.get('/api/market/my-awesome-product')
// response.data
{
"_id": "60fh4d37ac1a1c6f58d6a5f4",
"name": "My Awesome Product",
"slug": "my-awesome-product",
"price": 85.9,
"brand": "Apple"
}

Resources