How can I pass Express.js variables to MongoDB functions?

坚强是说给别人听的谎言 提交于 2020-05-29 06:24:31

问题


I am working on a blogging application (click the link to see the GitHub repo) with Express, EJS and MongoDB.

I have made a simple pager for the posts.

In the posts controller I have:

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);
};

The pager in the view:

<% 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>
<% } %>

The problem

The line .limit(perPage) from the controller gives the error perPage is not defined in the console (Git bash).

The solution that does not work

Clearly, I can move these 2 lines above const posts

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

but I can not do the same with const postsCount = posts.length; (which I also need in the view).

The objective

I am trying to make the snippet of code regarding the pagination reusable (like a plugin, if possible), since I need to paginate for the posts filtered by category, and also the list of post in the admin section o the application.

What am I doing wrong?


回答1:


why are you using callback and await together.seems like you need to look in to async / await and promises.What you can do is as below:

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
    });
  }
};



回答2:


As a comment correctly points out, this seems to be an issue of scoping.

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;
};

Move const perPage to above the const posts and it'll be within the correct scope/context.

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
};



回答3:


Maybe if you check this component, you can solve your problem by seeing how it works

Mongoose Paginate

$ 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);
 }
}



回答4:


As explained by other comments. This could just be a problem with scope.

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

        });
      }

  });

  // ..


for you problem with postsCount in the view, since you already have posts in you view

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

I think you can just use posts.length or postsCounts in the view like how you use the others(e.g pageIncrement, currPage, pageIncrement);




回答5:


As I found out recently postsCount = posts.length counts the posts after they are limited by .skip((currPage - 1) * perPage), so the pageIncrement variable "equation" turns to:

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

So I get, in the controller:

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);
};

And in the view:

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

and

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

That works fine unless there are is a number of posts equal to perPage x N, where N is an integer, in which case the "Older Posts" button becomes disabled one page too late.



来源:https://stackoverflow.com/questions/61718540/how-can-i-pass-express-js-variables-to-mongodb-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!