我该如何将Express.js的变量传递给MongoDB函数?

3
我正在开发一个使用Express、EJS和MongoDB的博客应用程序(点击链接查看GitHub存储库)。
我已经为文章制作了一个简单的分页器。
在文章控制器中,我有:
exports.getPosts = async (req, res, next) => {

  const posts = await Post.find({}, (err, posts) => {

      const perPage = 10;

      const currPage = req.query.page ? parseInt(req.query.page) : 1;

      const postsCount = posts.length;

      const pageCount = Math.ceil(postsCount / perPage);

      const pageDecrement = currPage > 1 ? 1 : 0;

      const pageIncrement = currPage < pageCount ? 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,
          pageDecrement: pageDecrement,
          pageIncrement: pageIncrement,
          posts: posts,
        });
      }
    })
      .sort({ created_at: -1 })
      .populate("category")
      .limit(perPage)
      .skip((currPage - 1) * perPage);
};

视图中的寻呼机:
<% if (posts) {%>
  <div class="clearfix d-flex justify-content-center">
    <div class="px-1">
        <a class="btn btn-primary <%= pageDecrement == 0 ? 'disabled' : '' %>" href="/?page=<%= currPage - pageDecrement %>">&larr; Newer Posts</a>
    </div>

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

问题:

问题

控制器中的代码行.limit(perPage) 在控制台(Git bash)中报错perPage未定义

解决方案:

无效的解决方案

显然,我可以将这两行移到const posts上面

const perPage = 5;
const currPage = req.query.page ? parseInt(req.query.page) : 1;

但我无法像处理 const postsCount = posts.length; 那样在视图中重复使用(这也是我需要的)。

目标

我试图将分页代码片段做成可重用的(如果可能的话,像插件一样),因为我需要对按类别过滤的帖子进行分页,并且还需在应用程序的管理员部分中对帖子列表进行分页。

我做错了什么?


我没有运行代码,但我认为 perPage 变量是正确的作用域。在 const posts 之前尝试定义它。 - Denis Lapadatovic
请查看这些答案,它们可以帮助您 Mongoose 分页 - Daniel Cabrera
5个回答

5
为什么要同时使用回调函数和await?似乎你需要研究一下async/await和promises。你可以按照以下方式进行操作:
exports.getPosts = async (req, res, next) => {
  const currPage = req.query.page ? parseInt(req.query.page) : 1;
  const perPage = 10;
  try {
    const posts = await Post.find({})
      .sort({ created_at: -1 })
      .populate("category")
      .limit(perPage)
      .skip((currPage - 1) * perPage).exec();

    const postsCount = posts.length;

    const pageCount = Math.ceil(postsCount / perPage);

    const pageDecrement = currPage > 1 ? 1 : 0;

    const pageIncrement = currPage < pageCount ? 1 : 0;
    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,
      pageDecrement: pageDecrement,
      pageIncrement: pageIncrement,
      posts: posts,
    });
  } catch (err) {
    console.log("Error: ", err);
    // add proper error handling here 
    res.render('default/error', {
      err
    });
  }
};

我认为你的 Post.find() 缺少了 errposts 参数。 - Razvan Zamfir
1
如果您使用async await,就不需要传递回调函数。 - Yalamber
未处理的 Promise 拒绝警告:引用错误:err 未定义 在 exports.getPosts (C:\Users\Asus\Desktop\XPressBlog\controllers\front-end\posts.js:23:3) 的第 23 行:if (err) { - Razvan Zamfir
尝试更新代码,它使用try catch进行错误处理,还要注意异步/等待和错误处理。 - Yalamber
让我们在聊天中继续这个讨论 - Razvan Zamfir

1
正如评论中正确指出的那样,这似乎是作用域的问题。
exports.getPosts = async (req, res, next) => {
  // getPosts local scope
  const posts = await Post.find({}, (err, posts) => {
      // ... local scope
      const perPage = 10;

      const currPage = req.query.page ? parseInt(req.query.page) : 1;

      const postsCount = posts.length;

      const pageCount = Math.ceil(postsCount / perPage);

      const pageDecrement = currPage > 1 ? 1 : 0;

      const pageIncrement = currPage < pageCount ? 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,
          pageDecrement: pageDecrement,
          pageIncrement: pageIncrement,
          posts: posts,
        });
      }
      // ... local scope ended
    })
      .sort({ created_at: -1 })
      .populate("category")
      // perPage == undefined
      .limit(perPage)
      .skip(currPage - 1)) * perPage;
};

const perPage 移动到 const posts 上方,这样它就在正确的作用域/上下文中了。
exports.getPosts = async (req, res, next) => {
  const perPage = 10;
  // getPosts local scope
  const posts = await Post.find({}, (err, posts) => {
      // ... rest of func
    });
  // .. rest of func
};

这个解决方案解决了一个问题,但同时也留下/创建了其他问题:我有一个使用posts变量的postsCount变量。 - Razvan Zamfir
你可以通过局部作用域引用外部作用域,但反过来不行。这篇文章可以比我更好地解释: https://scotch.io/tutorials/understanding-scope-in-javascript - Isolated

1
也许如果您检查这个组件,您可以通过了解其工作原理来解决问题。 Mongoose分页
$ npm install mongoose-paginate

/**
* querying for `all` {} items in `MyModel`
* paginating by second page, 10 items per page (10 results, page 2)
**/

MyModel.paginate({}, 2, 10, function(error, pageCount, paginatedResults) {
 if (error) {
   console.error(error);
 } else {
   console.log('Pages:', pageCount);
   console.log(paginatedResults);
 }
}

1
正如其他评论所解释的那样,这可能只是作用域问题。
exports.getPosts = async (req, res, next) => {
  const perPage = 10; // enable you to use perPage inside getPosts()
  let postsCount = 0; // let, to enable you to use/reassigned postsCount inside getPosts()
  const posts = await Post.find({}, (err, posts) => {
    // ...
    postsCount = posts.length; // updates the variable with the correct count
    // ...
    if (err) {
        console.log("Error: ", err);
      } else {
        res.render("default/index", {
          //...
          posts: posts,
          postsCount: posts.length, // for explicit postsCount in the view

        });
      }

  });

  // ..


针对您在视图中的“postsCount”问题,由于您已经在视图中有“posts”,因此需要进行调整。

<% if (posts) {%>
  ...
<% } %>

我认为你可以在视图中像使用其他变量(例如pageIncrement,currPage,pageIncrement)一样使用posts.lengthpostsCounts;


我已经这样做了,使用 var postsCount = 0;,因为我无法更改常量的值。 - Razvan Zamfir
1
你好 @harold-pogi,欢迎来到SO!下次请确保不仅仅发布代码,而是解释为什么这个解决方案可能有效以及有什么问题。这会帮助很多人! - phaberest
虽然这段代码可能解决了OP的问题,但最好还是解释一下你的代码如何解决OP的问题。这样,未来的访问者可以从您的帖子中学习,并将其应用于自己的代码中。SO不是编码服务,而是知识资源。此外,高质量、完整的答案更有可能被点赞。这些特点以及所有帖子都必须是自包含的要求,是SO作为一个平台的一些优势,使其与论坛区分开来。您可以编辑以添加其他信息和/或使用源文档补充您的解释。 - SherylHohman
谢谢。我已经更新了我的答案,还包括解释并添加了 postsCount - Harold Pogi

0

最近我发现postsCount = posts.length统计的是 .skip((currPage - 1) * perPage)限制条件后的帖子数量,因此pageIncrement变量的“方程式”变成:

let pageIncrement = postsCount >= perPage ? 1 : 0;

所以在控制器中我得到:

exports.getPosts = async (req, res, next) => {

    const perPage = 5;

    const currPage = req.query.page ? parseInt(req.query.page) : 1;

    let postsCount = 0;

    const posts = await 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是一个整数,在这种情况下,“旧帖子”按钮会比应该的晚一页被禁用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接