如何用mongoose和EJS实现分页并在分页时保留搜索query?

How to implement pagination with mongoose and EJS and keep the search query when paging?

我正在使用 Nodejs、EJS、Mongoose 和 MongoDB,并且我有一个 table 是根据我的数据库中的文档创建的,如果不清除我的搜索查询就无法使用分页按钮。

我的应用程序的工作方式是

  1. 单击搜索 link,这会打开一个搜索过滤器页面。 My Search page

  2. 然后你 select 你的文件管理器和搜索。然后显示结果。在 URL 中使用搜索查询 Searched Results with Search Query

3.When 你点击下一页它会清除你的查询。 Page buttons

这是我的寻呼按钮,下面是我的路线 我的搜索过滤器在另一页上。

<div class="container">
  <nav aria-label="...">
    <ul class="pagination float-right">
      <li class="page-item disabled">
        <span class="page-link">Previous</span>
      </li>
      <li class="page-item active">
        <a class="page-link" name="1" href="/searched/1">1</a>
      </li>
      <li class="page-item">
        <a class="page-link" name="2" href="/searched/2">2</a>
      </li>
      <li class="page-item">
        <a class="page-link" name="3" href="/searched/3">3</a>
      </li>
      <li class="page-item">
        <a class="page-link">Next</a>
      </li>
    </ul>
  </nav>
</div>

app.get("/searched/:page/:limit", function (req, res) {
  if (req.isAuthenticated()) {
    // const { page, limit } = req.params;

    // const options = {
    //   sort: { dateAdded: -1 },
    //   page: page,
    //   limit: limit,
    // };

    const query = req.query;

    if (query.btu === "") {
      delete query.btu;
    }

    if (query.sn1 === "") {
      delete query.sn1;
    }

    if (query.sn2 === "") {
      delete query.sn2;
    }

    if (query.userCreated === "") {
      delete query.userCreated;
    }

    if (query.split === "") {
      delete query.split;
    }

    if (query.supplier === "") {
      delete query.supplier;
    }

    if (query.issued === "") {
      delete query.issued;
    }

    // Aircon.paginate(query, options, function (err, foundAircons) {
    //   if (err) {
    //     console.log(err);
    //   } else {
    //     console.log(foundAircons);
    //     res.render("instock", {
    //       foundAircons: foundAircons.docs,
    //     });
    //   }
    // });

    Aircon.find(query)
      .sort({
        dateAdded: "desc",
      })
      .exec((err, foundAircons) => {
        if (err) {
          console.log(err);
        } else {
          res.render("instock", {
            foundAircons: foundAircons,
          });
        }
      });
  } else {
    res.redirect("/login");
  }
});

实际上,你的结构对我来说很陌生。我不确定您是否听说过“分页标记”一词。如果你没有,你可以查看 this 宏伟的指南。

我用 searchTermlimitpageToken 等参数编写了搜索端点以进行分页。 pageToken 很重要。如果你想去页面:例如2。 page token 应该是第一个记录在第一页结果的最后一个记录之后。我在这个例子中使用了 _id 参数

注意:必须创建索引才能过滤 searchTerm 的记录。索引创建是这样的: await db.collection(feedSettings._collection).createIndex({ "$**": "text" }, { name: "TextIndex" });

代码:

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

    const db = await database.mongo;
    const feedSettings = req.feedSettings;

    // Query parameters
    const limit = parseInt(req.query.limit) || 100;
    let searchTerm = req.query.searchTerm;
    let pageToken = req.query.pageToken;

    const query = { _feedName: feedSettings.name };

    // Start from last item
    let paginatedQuery = {
        _feedName: feedSettings.name,
        _id: { $gt: ObjectID(pageToken) },
        _trashed: { $ne: true }
    }

    // If we don't have a pageToken start from first item
    if (!pageToken) {
        let firstFeed = await db.collection(feedSettings._collection).findOne(query, { projection: { _id: 1 } });
        if (!firstFeed) {
            return res.status(200).json({
                success: 1,
                data: []
            });
        }
        paginatedQuery._id = { $gte: ObjectID(firstFeed._id) };
    }

    // If user doesn't want to search a term in items
    if (typeof searchTerm === 'string') {
        await db.collection(feedSettings._collection).createIndex({ "$**": "text" }, { name: "TextIndex" });
        paginatedQuery.$text = { $search: searchTerm };
    }

    feedsData = await db.collection(feedSettings._collection)
        .find(paginatedQuery)
        .limit(limit)
        .toArray();
    
    return res.status(200).json({
        success: 1,
        data: feedsData
    });
}

设法让它与 mongoose paginate v2 一起工作,并找到了一个函数来重建查询字符串并传回按钮

function objectToQueryString(obj) {
  var str = [];
  for (var p in obj)
    if (obj.hasOwnProperty(p)) {
      str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
    }
  return str.join("&");
}


app.get("/searched", function (req, res) {
  if (req.isAuthenticated()) {
    const { page } = req.query;

    const options = {
      sort: { dateAdded: -1 },
      page: !page ? 1 : page,
      limit: 20,
    };

    const query = req.query;

    delete query.page;

    if (query.btu === "") {
      delete query.btu;
    }

    if (query.sn1 === "") {
      delete query.sn1;
    }

    if (query.sn2 === "") {
      delete query.sn2;
    }

    if (query.userCreated === "") {
      delete query.userCreated;
    }

    if (query.split === "") {
      delete query.split;
    }

    if (query.supplier === "") {
      delete query.supplier;
    }

    if (query.issued === "") {
      delete query.issued;
    }

    var queryString = objectToQueryString(query);

    console.log(queryString);
    Aircon.paginate(query, options, function (err, results) {
      if (err) {
        console.log(err);
      } else {
        res.render("instock", {
          foundAircons: results.docs,
          total: results.totalDocs,
          hasPrev: results.hasPrevPage,
          hasNext: results.hasNextPage,
          pageCount: results.totalPages,
          page: results.page,
          url: queryString,
        });
      }
    });
  } else {
    res.redirect("/login");
  }
});

<div class="container">
  <nav aria-label="...">
    <ul class="pagination float-right">
      <% let prev = "disabled"; if(hasPrev){ prev = "" }; %>
      <li class="page-item <%= prev %>">
        <a class="page-link" href="/searched/?<%= url %>&page=<%= page - 1 %>"
          >Previous</a
        >
      </li>

      <% for(let i = 1; i <= pageCount; i++){ %> <% let active = ""; %>
      <%if(page === i) { active = "active"} %>
      <li class="page-item <%= active %>">
        <a class="page-link" name="1" href="/searched/?<%= url %>&page=<%= i %>"
          ><%= i %></a
        >
      </li>
      <% }; %> <% let next = "disabled"; if(hasNext){ next = "" }; %>
      <li class="page-item <%= next %>">
        <a class="page-link" href="/searched/?<%= url %>&page=<%= page + 1 %>"
          >Next</a
        >
      </li>
    </ul>
  </nav>
</div>