Mongoose: model not saving data passed to it - node.js

I'm trying to send an object full of data I scraped to a collection on my server. Problem is, it doesn't save whenever I send it to the backend. I'm sending the information to a collection named events. The content constantly sends back a success! You saved a new item. Everytime I check events, however,
it's empty. Here's my code:
Controller
var CronJob = require('cron').CronJob;
var scrape = require("../models/dataScrape");
//code requesting data...
for(var i = 0; i < titles.length; i++){
data.push({"festival" : titles[i], "date" : dates[i], "url" : links[i]});
}
var _id = "12345";
var body = {"_id" : _id, "events" : data};
var job = new CronJob('0*/1 * * * *', function(req, res){
scrape.eventList.find({}, function (err, count) {
if (!err && count.length == 0) {
var newEvents = new scrap.eventList(body);
newEvents.save(function(err, data){
if(error){
console.log("Error: " + err);
}else{
console.log("success! You saved a new item.");
}
});
}else{
scrape.eventList.update({_id: body._id}, body, function(err){
console.log("update");;
if(err){
console.log(err);
}else{
console.log("success! you updated an item.");
}
});
}
});
}
Model
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/BackYardBrewing");
var eventsSchema = mongoose.Schema({
id : {type : String},
events : [{
festival : String,
date : String,
url : String,
}],
})
module.exports = {
eventList : mongoose.model("event", eventsSchema),
}
I've used a very similar format on another model, and it saves data just fine. Any hints?

In the if statement of the save method if(error) should be if(err), error doesn't exist.
According to mongoose, your save method should be..
newEvents.save(function(err){
if(err){
console.log("Error: " + err);
}else{
console.log("success! You saved a new item.");
}
});
Or you can use the create method instead
scrap.eventList.create(newEvents, function(err, doc){
if(err)
{ console.log("Error:" + err);}
else{ console.log("success! You saved a new item.");}
});

Related

Can't access fields of MongoDB document in Node.Js

I'm using mongoose and express on my nodejs project.
Trying to get the data from here
app.get('/offers/:id', (req, res) =>{
//store the id from the url
var id = req.params.id;
//just a placeholder
var data = {title: "title", description:"description"};
//store the returned object in a variable
var oop = offers.findById(id, function (err, user) {
if(err){
return err;
}else{
title = user.title;
description = user.description;
this.obj = {
title:title,
description:description
}
console.log(obj)
return obj;
}
} );
console.log(oop)
res.render('single', {data:data});
});
so my idea is to grab the post id from the url, find it in the database, then display the title and description in the corresponding place on the ejs template, but for some reason I can't access the returned data, and what I get is a long list of objects that belongs to mongodb, without the presence of "title" or "description"
Try this, your code has couple of issues & also you need use .lean() to get raw Js objects rather than mongoDB documents :
app.get('/offers/:id', (req, res) => {
//store the id from the url
var id = req.params.id;
//just a placeholder
var data = { title: "title", description: "description" };
//store the returned object in a variable
offers.findById(id).lean().exec((err, user) => {
if (err) {
console.log(err);
res.send(err)
} else {
data.title = user.title;
data.description = user.description;
this.obj = {
title: title,
description: description
}
console.log(obj);
res.render('single', { data: data });
// (Or) res.render('single', { data: obj });
}
});
});
I just modified your code and added comments (all starting with "***").
app.get('/offers/:id', (req, res) =>{
//store the id from the url
var id = req.params.id;
//just a placeholder
var data = {title: "title", description:"description"};
//store the returned object in a variables
// var oop = ***no need for this, the data you want will be in the user variable.
offers.findById(id, function (err, user) {
if(err){
return err;
}else{
// ***this needs to be changed to...
// title = user.title;
// description = user.description;
// ***that...
data.title = user.title;
data.description = user.description;
// ***what's that for??
// this.obj = {
// title:title,
// description:description
// }
// ***this needs to be inside mongoose's callback
res.render('single', {data:data});
}
});
});

deleting route for an array in mongodB using node.js

var userSchema=new mongoose.Schema({
username:String,
password:String,
email:String,
tasks:[{
task: String
}]
});
This is my database schema.I want to create a delete route for the task to be removed.Can anyone tell me how to do so. Right now I am able to fetch the task id.
Here is link to my c9 project https://ide.c9.io/akspan12/newprojectworkspace
var express = require('express');
var router = express();
//I will take static values you can give dynamic values by using req.body
router.post('/Delete_User_Task',function(req,res){
var UserSchema = require('/path/to/Schema.js');//your schema model path
var username = 'akshansh123'; //assume it is present in db
//If you want to remove all task of this user and set one task as empty string your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$set:{
'tasks':[{
task:''
}]
}
};
//If you completely want to remove json array tasks from user document than your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$unset:{
'tasks':''
}
};
//If you want to remove particular task suppose say sleeping from user document than your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$pull:{
'tasks':{
'task':'sleeping'
}
}
};
//If you want to remove selected tasks suppose say sleeping,walking,drinking from user document than your query and changes will be like below
var query = {
'username' :username
};
var changes = {
$pull:{
'tasks':{
'task':{
$in:['sleeping','walking','drinking']
}
}
}
};
UserSchema.update(query,changes,function(err,Result){
if(!err){
res.send('Successfully Removed tasks');
}else{
res.send('something went wrong');
console.log(err);
}
})
})
Hope this may solve your issue!!!
app.patch("/todo/:id",function(req,res){
User
.findById(req.user.id, function(err, foundUser) {
if(err){
req.flash("error",err.message);
console.log(err);
return res.redirect("back");
} if(!foundUser) {
req.flash("error","User not found");
return res.redirect("back");
} else {
foundUser.update({$pull: {tasks: {_id: req.params.id}}}, function(err) {
if(err) {
req.flash("error",err.message);
console.log(err);
return res.redirect("back");
} else {
req.flash("success","Task removed");
return res.redirect("/todo");
}
});
}
});
});
This is the delete route I used.

Mongodb schema defining

Coding a news/media website, I want a "News" section, "Reviews" section, a
"Trending" section, which combines both the previous sections, just like here:
I have made one schema for "News", one for "Reviews".How can I make a "Trending" section(as in the image above "Movies" section)?
Code :
In app.js,
//LANDING PAGE
app.get('/', function (req, res,next) {
Blogdemo.find({}).sort([['_id', -1]]).limit(3).exec(function(err,allBlogs) { //finds latest posts for 1st Schema (upto 3)
if(err) {
console.log(err);
next();
} else {
res.locals.blog = allBlogs;
// res.render("landing", {blog : allBlogs , moment : now});
next();
}
})
}, function (req, res) {
Review.find({}).sort([['_id', -1]]).limit(3).exec(function(err,allReviews) { //finds latest posts of 2nd Schema
if(err) {
console.log(err);
} else {
res.locals.review = allReviews;
res.render("landing", res.locals);
}
})
})
In review.js ,
var mongoose = require("mongoose");
//SCHEMA SETUP
var reviewSchema = new mongoose.Schema({
image : String,
title : String,
body : String,
rating : String,
created : {type : Date, default : Date.now()},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment" //name of the model
}
]
})
module.exports = mongoose.model("review", reviewSchema);
The "News" schema is almost the same(no review).
Is my way of defining schema wrong? If not, then how can I build the "Trending" section?
Is there any mongodb method which can find the latest posts from "News" and "Reviews" to build the "Trending" section(just like in 1st picture)?
From what i can see from your code, your current News and Review Schema looks fine.
You need to define another Schema for Trending.
var TrendingSchema = new mongoose.Schema({
referenceId : {
type : mongoose.Schema.Types.ObjectId
},
postType : String //To store News or Reviews
});
While saving new News or Reviews, insert the _id of newly saved document in the trending collection.
var news = new News();
news.image = newsImage;
...
news.save(function(err,result)
{
if(!err)
{
var trending = new Trending();
trending.referenceId = result._id;
trending.postType = "News";
treding.save(function(err)
{
if(!err)
{
//success response
}
else
{
//error response
}
});
}
else
{
//send error response
}
});
Similarly while saving Review Post
var review = new Review();
review.image = reviewImage;
...
review.save(function(err,result)
{
if(!err)
{
var trending = new Trending();
trending.referenceId = result._id;
trending.postType = "review"
treding.save(function(err)
{
if(!err)
{
//success response
}
else
{
//error response
}
});
}
else
{
//send error response
}
});
Thus now Trending Collection will contain, newly saved News or Review, in the order they are created. Thus you will be able to get new Review or News Post.
While fetching Trending, you can populate them using News or Review Schema based on the postType.
Trendign.find({}).limit(10).exec(function(err,result)
{
if(!err && result.length!=0)
{
var trendingPosts = [];
result.forEach(function(trending){
if(trending.postType === "News"){
trending.populate({path : 'referenceId',model : 'News'},function(err,populatedItem)
{
if(!err)
{
trendingPosts.push(populatedItem);
}
});
}
else if(trending.postType === "Review"){
trending.populate({path : 'referenceId',model : 'Review'},function(err,populatedItem)
{
if(!err)
{
trendingPosts.push(populatedItem);
}
});
}
});
//now send the trendingPost array with latest News and Review Posts
}
else
{
//send Error response
}
});
Now you can show the latest News or Review and write the type postType.
Hope this is what you want.

MongoDB mongoose subdocuments created twice

I am using a simple form that can be used to register an article to a website.
the back-end looks like this:
// Post new article
app.post("/articles", function(req, res){
var newArticle = {};
newArticle.title = req.body.title;
newArticle.description = req.body.description;
var date = req.body.date;
var split = date.split("/");
newArticle.date = split[1]+'/'+split[0]+'/'+split[2];
newArticle.link = req.body.link;
newArticle.body = req.body.body;
var platforms = req.body.platforms;
console.log(platforms);
Article.create(newArticle, function(err, createdArticle){
if(err){
console.log(err.message);
} else {
var counter=0;
platforms.forEach(function(platform){
var platformed=mongoose.mongo.ObjectID(platform);
Platform.findById(platformed, function(err, foundPlatform){
if(err){
console.log(err);
} else {
counter++;
foundPlatform.articles.push(createdArticle);
foundPlatform.save();
createdArticle.platforms.push(foundPlatform);
createdArticle.save();
if(counter==platforms.length){
res.redirect('articles/' + createdArticle._id);
}
}
});
});
}
});
});
The platforms field is passed to the back-end as an array of strings, one string being one objectID. When platforms only contains 1 string i.e. 1 platform to be linked to, everything works fine. When platforms contains multiple string. the created article has duplicates of each platform. Or sometimes only duplicates of some platforms
Any ideas?
UPDATE 1:
Article Schema:
var mongoose = require("mongoose");
var articleSchema = new mongoose.Schema({
title : String,
description : String,
link : String,
date : String,
body : String,
platforms : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Platform"
}
]
})
module.exports = mongoose.model("Article", articleSchema);
Platform Schema:
var mongoose = require("mongoose");
var platformSchema = new mongoose.Schema({
name : String,
category : String,
contacts : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Contact"
}
],
website : String,
country : String,
contactInformation : String,
businessModelNotes : String,
source : String,
generalNotes : String,
projects : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Project"
}
],
articles : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Article"
}
],
privacy : String,
comments : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
module.exports = mongoose.model("Platform", platformSchema);
The forEach loop in your attempt does not recognise the callback completion of the findById() async method before the next iteration. You need to use any of async library methods async.each, async.whilst, or async.until which are equivalent to a for loop, and will wait until async's callback is invoked before moving on to the next iteration (in other words, a for loop that will yield).
For example:
var platform_docs = [];
async.each(platforms, function(id, callback) {
Platform.findById(id, function(err, platform) {
if (platform)
platform_docs.push(platform);
callback(err);
});
}, function(err) {
// code to run on completion or err
console.log(platform_docs);
});
For the whole operation, you could use the async.waterfall() method which allows each function to pass its results on to the next function.
The first function in the method creates the new article.
The second function uses the async.each() utility function to iterate over the platforms list, perform an asynchronous task for each id to update the platform using findByIdAndUpdate(), and when they're all done return the results of the update query in an object variable to the next function.
The final function will update the newly created article with the platform ids from the previous pipeline.
Something like the following example:
var newArticle = {},
platforms = req.body.platforms,
date = req.body.date,
split = date.split("/");
newArticle.title = req.body.title;
newArticle.description = req.body.description;
newArticle.date = split[2]+'/'+split[0]+'/'+split[2];
newArticle.link = req.body.link;
newArticle.body = req.body.body;
console.log(platforms);
async.waterfall([
// Create the article
function(callback) {
var article = new Article(newArticle);
article.save(function(err, article){
if (err) return callback(err);
callback(null, article);
});
},
// Query and update the platforms
function(articleData, callback) {
var platform_ids = [];
async.each(platforms, function(id, callback) {
Platform.findByIdAndUpdate(id,
{ "$push": { "articles": articleData._id } },
{ "new": true },
function(err, platform) {
if (platform)
platform_ids.push(platform._id);
callback(err);
}
);
}, function(err) {
// code to run on completion or err
if (err) return callback(err);
console.log(platform_ids);
callback(null, {
"article": articleData,
"platform_ids": platform_ids
});
});
},
// Update the article
function(obj, callback) {
var article = obj.article;
obj.platform_ids.forEach(function(id){ article.platforms.push(id); });
article.save(function(err, article){
if (err) return callback(err);
callback(null, article);
});
}
], function(err, result) {
/*
This function gets called after the above tasks
have called their "task callbacks"
*/
if (err) return next(err);
console.log(result);
res.redirect('articles/' + result._id);
});
Move your save function
if(counter==platforms.length){
createdArticle.save(function(err, savedObject){
if(err || !savedObject) console.log(err || "not saved");
else {
res.redirect('articles/' + savedObject._id.toString());
}
});
}
============= EDIT
Its because you have to call article.save only one time, and not at each loop. In addition you use save() as a sync function but it's async.
I thinks you should use directly update function :
} else {
var counter=0;
// map plateform array id with ObjectID
var idarray = platforms.map(function(e){return mongoose.mongo.ObjectID(e);});
// update all plateform with article id
Platform.update({_id:{$in: idarray}}, {$push:{articles: createdArticle}}, {multi:true, upsert:false}, function(err, raw){
if(err)
{
// error case
return res.status(403).json({});
}
// retrieve plateform
Platform.find({_id:{$in: idarray}}, function(err, results){
if(err || !results)
{
// error case
return res.status(403).json({});
}
Article.update({_id: createdArticle._id.toString()}, {$push:{platforms:{$each: results}}}, {multi:false, upsert:false}, function(err, saved){
if(err || !saved)
{
// error
return res.status(403).json({});
}
res.redirect('articles/' + savedObject._id.toString());
});
});
});
But it's a bad idea to store full objects, why not storing only id ??

Server not responding to url with parameters

I'm attempting to create a server for now should be able to register users.
However the server doesn't react when attempting to register using /reg.
When I create a new .get it does respond though, so the server itself is working.
What also is unclear to me is how to correctly format the url.
app.post('/reg/:uname/:teamid', function(req, res){
var username = req.params.uname;
var teamidpar = req.params.teamid;
UserSchema.pre('save', function (next) {
this1 = this;
UserModel.find({uname : this1.username}, function(err, docs) {
if (!docs.length) {
//Username already exists
} else {
var loginid = randomstring.generate();
var newUser = User({
uname : username,
teamid : teamidpar,
totalscore : 0,
lastopponement : null,
gamescore : 0,
});
User.save(function (err, User, next) {
if (err) {return console.error(err);}
else
{console.log(timestamp+':'+'User created:'+newUser.uname+':'+newUser.login);}
res.json({login : loginid});
});
}
});
});
});
I don't know why I didn't see this earlier, but you use UserSchema.pre at the beginning, however this is just a definition and will not be immediately executed. Only when you actually do a save on a document will this function be triggered.
Below the correct, edited version.
app.post('/reg/:uname/:teamid', function(req, res) {
var username = req.params.uname;
var teamidpar = req.params.teamid;
// If you are just checking if something exist, then try count
// as that has minimal impact on the server
UserModel.count({uname : username}, function(err, count) {
if (count > 0) {
// Username already exists, but always output something as we
// don't want the client to wait forever
return res.send(500);
}
var loginid = randomstring.generate();
// You'll need a new instance of UserModel to define a new document
var newUser = new UserModel({
uname : username,
teamid : teamidpar,
totalscore : 0,
lastopponement : null,
gamescore : 0,
});
// Save the document by calling the save method on the document
// itself
newUser.save(function (err) {
if (err) {
console.error(err);
// You'll want to output some stuff, otherwise the client keeps on waiting
return res.send(500);
}
console.log(timestamp + ': User created:' + username + ':' + loginid);
res.json({login : loginid});
});
});
});

Resources