How to paginate populated comments? - express

I'm trying to paginate comments on articles in my project. Unfortunately, it only shows the first five (in my case) comments on any page. Can anyone suggest what is my mistake?
exports.getNews = async (req, res, next) => {
const commentPerPage = 5
const page = req.params.page || 1
try {
const news = await News.findOne({ slug: req.params.news_slug })
.populate({
path: 'comments',
options: {
skip: (page - 1) * commentPerPage,
limit: commentPerPage,
}
}).exec()
const commentCount = await Comment.count({})
.exec()
if (news) {
// News view counter
news.incrementViewsCounter()
return res.render('news/news_body', {
news,
currentPage: page,
pages: Math.ceil(commentCount / commentPerPage),
})
}
res.status(404)
} catch (err) {
next(err)
}
}

Related

infinity loading when try to scrap title article with cheerio

infinity loading when try to scrap title article
i was trying to scrap title articles with cheerio in node js but i could not make it happen
infinity loading in google chrome and no content . here is my controller.js file that i trying to use cheerio to scrap title articles with cheerio and show handlesbars view engine
but view engie is working and everything is fine . but for scrap infinity loading in chrome with no error
classname that i use for this website is .c-entry-box--compact__title
maybe i am wrong . but i can not figure out
var express = require("express");
var router = express.Router();
var path = require("path");
var request = require("request");
var cheerio = require("cheerio");
var Comment = require("../models/Comment.js");
var Article = require("../models/Article.js");
router.get("/", function(req, res) {
res.redirect("/articles");
});
router.get("/scrape", function(req, res) {
request("http://www.theverge.com", function(error, response, html) {
var $ = cheerio.load(html);
var titlesArray = [];
$(".c-entry-box--compact__title").each(function(i, element) {
var result = {};
result.title = $(this)
.children("a")
.text();
result.link = $(this)
.children("a")
.attr("href");
if (result.title !== "" && result.link !== "") {
if (titlesArray.indexOf(result.title) == -1) {
titlesArray.push(result.title);
Article.count({ title: result.title }, function(err, test) {
if (test === 0) {
var entry = new Article(result);
entry.save(function(err, doc) {
if (err) {
console.log(err);
} else {
console.log(doc);
}
});
}
});
} else {
console.log("Article already exists.");
}
} else {
console.log("Not saved to DB, missing data");
}
});
res.redirect("/");
});
});
router.get("/articles", function(req, res) {
Article.find()
.sort({ _id: -1 })
.exec(function(err, doc) {
if (err) {
console.log(err);
} else {
var artcl = { article: doc };
res.render("index", artcl);
}
});
});
router.get("/articles-json", function(req, res) {
Article.find({}, function(err, doc) {
if (err) {
console.log(err);
} else {
res.json(doc);
}
});
});
router.get("/clearAll", function(req, res) {
Article.remove({}, function(err, doc) {
if (err) {
console.log(err);
} else {
console.log("removed all articles");
}
});
res.redirect("/articles-json");
});
router.get("/readArticle/:id", function(req, res) {
var articleId = req.params.id;
var hbsObj = {
article: [],
body: []
};
Article.findOne({ _id: articleId })
.populate("comment")
.exec(function(err, doc) {
if (err) {
console.log("Error: " + err);
} else {
hbsObj.article = doc;
var link = doc.link;
request(link, function(error, response, html) {
var $ = cheerio.load(html);
$(".l-col__main").each(function(i, element) {
hbsObj.body = $(this)
.children(".c-entry-content")
.children("p")
.text();
res.render("article", hbsObj);
return false;
});
});
}
});
});
router.post("/comment/:id", function(req, res) {
var user = req.body.name;
var content = req.body.comment;
var articleId = req.params.id;
var commentObj = {
name: user,
body: content
};
var newComment = new Comment(commentObj);
newComment.save(function(err, doc) {
if (err) {
console.log(err);
} else {
console.log(doc._id);
console.log(articleId);
Article.findOneAndUpdate(
{ _id: req.params.id },
{ $push: { comment: doc._id } },
{ new: true }
).exec(function(err, doc) {
if (err) {
console.log(err);
} else {
res.redirect("/readArticle/" + articleId);
}
});
}
});
});
module.exports = router;
The http://www.theverge.com Add content dynamically by scrolling.
This is example how to get the title by puppeteer
const puppeteer = require("puppeteer");
const getTitle = async () => {
try {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(0);
await page.goto('https://www.theverge.com');
await page.setViewport({
width:1920,
height:1080
});
// scroll down end of page
await page.evaluate(() => {
window.scrollTo(0, window.document.body.scrollHeight);
});
await page.waitForNavigation({ waitUntil: 'networkidle0' }), // (0 network connections for 500ms)
// get the title
titles = await page.evaluate(() => {
const textSelector = 'div.inline.pr-4.font-bold'
texts = Array.from(document.querySelectorAll(textSelector), row => row.innerText.trim() );
return texts;
});
await browser.close();
return Promise.resolve(titles);
} catch (error) {
return Promise.reject(error);
}
}
getTitle()
.then((titles) => {
console.log(titles); // first news search
})
This is result
[
'Is an upgraded M2 Ultra enough for a new Mac Pro and the Mac Studio?',
'Here’s the official trailer for Christopher Nolan’s next IMAX-filmed epic, Oppenheimer.',
'Sam Bankman-Fried’s ready to surrender himself to the US for extradition.',
'Who knew the thumb drive had such a contentious origin story?',
'But how many pebbles do you have in a jar?',
'This way for The Way of Water.',
'Netflix is taking Blockbuster behind the woodshed again.',
'I can’t escape the year-end wrap-ups.',
'The clock’s ticking if you want to get your gifts on time.',
'Want solar panels on your California home? Now might be the time.',
'Twitter Spaces has returned.',
'Apple’s facing another accusation of breaking labor laws.',
'Every game should have this feature.',
'Google’s working on simplifying smart home control on the wrist.',
'Apple could open up iOS, and the feds finally make a case against SBF.',
'I’m not the first, and I won’t be the last... but I do feel early.',
'For what it’s worth, Avatar: The Way of Water’s a good looking movie.',
'You may not want to upgrade to Apple’s new Home architecture.'
]

Changing the collection based on the request type

This controller accepts the form and updates the data.
export const createPost = async (req, res) => {
const { title, message, selectedFile, creator, tags } = req.body;
const newPostMessage = new OrangeModel ({ title, message, selectedFile, creator, tags })
try {
await newPostMessage.save();
res.status(201).json(newPostMessage );
} catch (err) {
res.status(409).json({ message: err.message });
}
}
I want to change the collection type based on the request.
when the request is from the Grapes url, the model(or collection) should change to GrapeModel from OrangeModel. How to do this?
If you want a POST /Grapes to be behave differently from a POST /Oranges, you can attach your controller to both paths and evaluate the path inside your code.
const createPost = async (req, res) => {
let newPostMessage;
if (req.path === "/Oranges") newPostMessage = new OrangeModel(...);
else if (req.path === "/Grapes") newPostMessage = new GrapeModel(...);
try {
await newPostMessage.save();
...
};
app.post(["/Oranges", "/Grapes"], createPost);
Also I got the answer like this:
exports.createPost =Model=> async (req, res) => {
try {
const doc = await Model.create(req.body, {
new: true,
runValidators: true,
});
res.status(200).json({
status: 'success',
data: {
doc,
},
});
} catch (error) {
res.status(400).json({
status: 'fail',
message: error,
});
}
};
Here just call createPost function with the model name

Request body is empty when submitting data using "form data"

When I update using raw JSON, it's working but when I use the form data it is not updating. the request body when using form data is an empty object. Why is this happening?
Here's my update code:
exports.updateProgram = catchAsync(async (req, res, next) => {
console.log('req ko body',req.body)
let doc = await Program.findByIdAndUpdate(req.params.id, req.body, { runValidators: true, new: true })
if (!doc) {
return next(new AppError('No document found with that ID', 404))
}
res.status(200).json({
status: 'success!',
data: { doc }
})
})
In Postman:
I am using multer, I actually pass the photo in req.body. Here's the code:
let multerStorage = multer.memoryStorage()
let multerFilter = (req, file, cb) => {
if (file.mimetype.split('/')[0] == 'image') {
cb(null, true)
} else {
cb(new AppError('Not an image!', 400), false)
}
}
let upload = multer({
storage: multerStorage,
fileFilter: multerFilter
})
exports.uploadPhotos = upload.fields([
{ name: 'abcd', maxCount: 10 },
{ name: 'photos', maxCount: 10 },
{name: 'photos3', maxCount: 10}
])
exports.resizePhotos = catchAsync(async (req, res, next) => {
// if (!req.files.photos || !req.files.abcd) return next()
if(req.files.abcd) {
req.body.abcd = []
await Promise.all(req.files.abcd.map(async (file, i) => {
let filename = `tour-${Date.now()}-${i + 1}.jpeg`
await sharp(file.buffer)
.resize(500,500)
.toFormat('jpeg')
.jpeg({ quality: 90 })
.toFile(`public/img/arpit/${filename}`)
req.body.abcd.push(filename)
})
)} else if(req.files.photos3) {
req.body.photos3 = []
await Promise.all(req.files.photos3.map(async (file, i) => {
let filename = `tour-${Date.now()}-${i + 1}.jpeg`
await sharp(file.buffer)
.resize(500,500)
.toFormat('jpeg')
.jpeg({ quality: 90 })
.toFile(`public/img/arpit/${filename}`)
req.body.photos3.push(filename)
})
)}
else if(req.files.photos) {
// console.log('codee here')
// } else if(req.body.photos) {
req.body.photos = []
console.log('req.files>>>', req.files)
await Promise.all(req.files.photos.map(async (file, i) => {
let filename = `tour-${Date.now()}-${i + 1}.jpeg`
await sharp(file.buffer)
.resize(500,500)
.toFormat('jpeg')
.jpeg({ quality: 90 })
.toFile(`public/img/programs/${filename}`)
req.body.photos.push(filename)
})
)
}
return next()
})
I'm importing in the routes file
Express (bodyParser) can't handle multipart form-data and that's why your code isn't working.
Take a look at multer, an express package. It is a middleware which provides the functionality you're looking for.
var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]);
app.post('/cool-profile', cpUpload, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body will contain the text fields, if there were any
})
This might be help you. Quoted from https://www.npmjs.com/package/multer#readme

comments not displaying on express app

I was watching a tutorial on a creating a restful app. I tried to my own project that was a little different from the tutorial and I am now stuck. I am trying to associate my Comments collection with Blog collection but data is not showing on my show page. I am having a hard time figuring out why my comments are not displaying on my blog post.
app.js file
var bodyParser = require('body-parser'),
methodOverride = require('method-override'),
expressSanitizer = require("express-sanitizer"),
mongoose = require('mongoose'),
express = require('express'),
app = express(),
Blog = require("./models/blog"),
Comment = require('./models/comment'),
seedDB = require("./seeds");
seedDB();
//APP CONFIG
mongoose.connect("mongodb://localhost:27017/blogApp", { useNewUrlParser: true
);
app.set("view engine", "ejs");
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressSanitizer());
app.use(methodOverride("_method"));
// SHOW Route
app.get("/blog/:id", function (req, res) {
Blog.findById(req.params.id).populate("Comments").exec(function (err, foundBlog) {
if (err) {
console.log(err);
res.redirect("/blog");
} else {
console.log(foundBlog);
res.render("show", { blog: foundBlog });
}
});
});
Seed file
var mongoose = require("mongoose")
var Blog = require("./models/blog");
var Comment = require("./models/comment")
function seedDB() {
Blog.remove({}, function (err) {
if (err) {
console.log(err);
} else {
console.log("Removed Blogs");
}
data.forEach(function (seed) {
Blog.create(seed, function (err, blog) {
if (err) {
console.log(err)
} else {
console.log("blog created");
Comment.create(
{
text: "That was one great blog post",
author: "Homer"
}, function (err, comment) {
if (err) {
console.log(err)
} else {
blog.comments.push(comment);
comment.save();
console.log("created new comment");
}
}
)
}
})
});
});
}
comment model
var mongoose = require("mongoose");
var commentSchema = new mongoose.Schema({
text: String,
author: String
})
var Comment = mongoose.model("Comment", commentSchema);
module.exports = Comment
blog model
var blogSchema = new mongoose.Schema({
title: String,
image: String,
body: String,
created: { type: Date, default: Date.now },
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
})
var Blog = mongoose.model("Blog", blogSchema);
module.exports = Blog
On my show.ejs page here is my code to try and display the comment but nothing populates
<% blog.comments.forEach(function(comment){ %>
<p><strong><%= comment.author %></strong> - <%= comment.text %> </p>
<% }) %>
here is my result from console.log in show route
{ comments: [],
_id: 5b666ed86feec81af8651b9b,
title: 'Test Blog 2',
image: 'https://images.unsplash.com/photo-1499938971550-7ad287075e0d?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=d787d5e47840a5a0a6ff7574c90a02d7&auto=format&fit=crop&w=500&q=60',
body: 'Hello this is a blog post',
created: 2018-08-05T03:28:24.404Z,
__v: 0 }
Please help me figure out why comments are not showing
I believe the issue is with this line
Blog.findById(req.params.id).populate("Comments").exec(function (err, foundBlog)
instead of populate("Comments") it should be populate("comments")
Try to execute once with the above change.

Using async / await with mongoose.js

Looking for help to rewrite these 2 queries using async / await instead of using the nested callbacks approach.
exports.post_edit_get = function(req, res, next) {
var id = req.params.id;
if (mongoose.Types.ObjectId.isValid(id)){
POST.findById(id, function (err, doc){
if (err) { return next(err); }
playerQuery.exec(function (err, players){
if (err) { return next(err); }
res.render('posts/posts_admin', { title: pageTitle, formData: doc, players: players });
});
});
}else{
res.send("Invalid ID");
};
};
Here you go
const { isValid } = mongoose.Types.ObjectId
exports.post_edit_get = async function(req, res, next) {
var { id } = req.params;
if (!isValid(id)){
return res.send("Invalid ID");
}
try {
const post = await POST.findById(id)
const players = await playerQuery.exec()
res.render('posts/posts_admin', {
title: pageTitle,
formData: doc,
players: players
})
} catch (err) {
return next(err)
}
}
If you want to get rid of these try/catches at the route handler level you'll want to have a look at this post; Using async/await to write cleaner route handlers