如何计算集合中的所有文档,并在控制器中使用cont,使用MongoDB和Express.js?



我正在使用Express(版本4.17.1(,EJS和MongoDB(版本4.0.10(开发博客应用程序(单击链接以查看GitHub存储库(。

尝试对帖子进行分页,我在控制器中执行以下操作:

exports.getPosts = (req, res, next) => {
const perPage = 5;
const currPage = req.query.page ? parseInt(req.query.page) : 1;
let postsCount = 0;
const posts = Post.find({}, (err, posts) => {
postsCount = posts.length;
let pageDecrement = currPage > 1 ? 1 : 0;
let pageIncrement = postsCount >= perPage ? 1 : 0;
if (err) {
console.log('Error: ', err);
} else {
res.render('default/index', {
moment: moment,
layout: 'default/layout',
website_name: 'MEAN Blog',
page_heading: 'XPress News',
page_subheading: 'A MEAN Stack Blogging Application',
currPage: currPage,
posts: posts,
pageDecrement: pageDecrement,
pageIncrement: pageIncrement
});
}
})
.sort({
created_at: -1
})
.populate('category')
.limit(perPage)
.skip((currPage - 1) * perPage);
};

在观点中:

<a class="btn btn-primary <%= pageDecrement == 0 ? 'disabled' : '' %>" href="/?page=<%= currPage - pageDecrement %>">&larr; Newer Posts</a>

<a class="btn btn-primary <%= pageIncrement == 0 ? 'disabled' : '' %>" href="/?page=<%= currPage + pageIncrement %>">Older Posts &rarr;</a>

除非有许多帖子等于perPage x N,其中 N 是整数,否则这工作正常,在这种情况下,"旧帖子"按钮被禁用一页太晚了。

那是因为postsCount = posts.length在受到.skip((currPage - 1) * perPage)限制计算帖子。

所以我需要计算模型/集合中的帖子并将该计数变量引入控制器

我的模型:

const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
short_description: {
type: String,
required: true
},
full_text: {
type: String,
required: true
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category'
},
post_image: {
type: String,
required: false
},
updated_at: {
type: Date,
default: Date.now()
},
created_at: {
type: Date,
default: Date.now()
}
});
module.exports = mongoose.model('Post', postSchema);

如何计算帖子集合中的所有文档并在帖子控制器中使用该编号?

这可以通过mongodb聚合框架更容易完成。

我们使用$facet聚合来获取分页数据以及文档总数。

在聚合框架中,我们使用$lookup而不是猫鼬填充。 $lookup返回一个数组,以获取数组中的第一个项目,我们在$addFields中使用$arrayElemAt运算符。

操场

以下是应用于您的应用的代码: (这里不需要第一个$match聚合,但我放进去以防将来可能需要它(

exports.getPosts = async (req, res, next) => {
const perPage = 5;
const currPage = req.query.page ? parseInt(req.query.page) : 1;
const skip = (currPage - 1) * perPage;
try {
const result = await Post.aggregate([{
$match: {},
},
{
$sort: {
created_at: -1,
},
},
{
$lookup: {
from: "categories",
localField: "category",
foreignField: "_id",
as: "category",
},
},
{
$addFields: {
category: {
$arrayElemAt: ["$category", 0],
},
},
},
{
$facet: {
totalRecords: [{
$count: "total",
}, ],
data: [{
$skip: skip,
},
{
$limit: perPage,
},
],
},
},
]);
let postsCount = result[0].totalRecords[0].total;
const pageCount = Math.ceil(postsCount / perPage);
const pageDecrement = currPage > 1 ? 1 : 0;
const pageIncrement = currPage < pageCount ? 1 : 0;
const posts = result[0].data;
res.render("default/index", {
moment: moment,
layout: "default/layout",
website_name: "MEAN Blog",
page_heading: "XPress News",
page_subheading: "A MEAN Stack Blogging Application",
currPage,
posts,
pageDecrement,
pageIncrement,
});
} catch (err) {
console.log("Error: ", err);
res.status(500).send("something went wrong");
}
};

顺便说一下,在帖子架构中,对于您使用的日期字段default: Date.now(),这将导致日期值始终相同的值,它应该采用以下格式:default: Date.now

Read $facet。

版本 3.4 中的新功能。

在单个阶段内处理多个聚合管道 同一组输入文档。每个子管道都有自己的字段 输出文档,其结果存储为 文件。

示例:请参阅此处

db.collection.aggregate([
{
$facet: {
"count": [
{ $match: {} },
{ $count: "totalCount" }
],
"data": [
{ $match: {} },
{ $sort: { _id: -1 } },
{ $skip: 1 },
{ $limit: 2 }
]
}
}
])

猫鼬版:

Model.aggregate([
{
$facet: {
"count": [
{ $match: {} },
{ $count: "totalCount" }
],
"data": [
{ $match: {} },
{ $sort: { _id: -1 } },
{ $skip: 1 },
{ $limit: 2 }
]
}
}
]).
then(res => console.log(res)).
catch(error => console.error('error', error));

如果是猫鼬,你应该使用这个:

https://mongoosejs.com/docs/api.html#aggregate_Aggregate-facet

官方Mongodb文档:

https://docs.mongodb.com/manual/reference/operator/aggregation/facet

一般的想法是执行聚合而不是多次调用(1 用于获取所需信息 + 1 用于获取文档总数(

当然,您可以执行 2 个单独的调用,但它会影响您的性能(对于小数据量来说不多,但仍然...... 因此,您可以使用 .find(( 获取所有需要的数据,然后像这样获取计数: https://mongoosejs.com/docs/api.html#model_Model.count

顺便说一句,使用异步/等待而不是回调来避免回调地狱

最新更新