How best to add pagination to a search result query in Reactjs? - javascript

I have a MERN stack application and I have written the search query and pagination in Nodejs, I implemented the pagination part in Reactjs and wanted to implement the search query too. It is working but without pagination. I was like what if the search result is over 20 results and I simply want to make it two pages. I could do something like 12 search results per page. Is there a way to do this? Can I add both search and pagination queries in a single URL? Here is my nodejs code:
const DEFAULT_PAGE_NUMBER = 1
const DEFAULT_PAGE_LIMIT = 12;
const getPagination =(query) =>{
const page = Math.abs(query.page) || DEFAULT_PAGE_NUMBER;
const limit = Math.abs(query.limit) || DEFAULT_PAGE_LIMIT;
const skip = (page -1) * limit
return {
skip,
limit
};
};
const getAllPosts = async (req, res) =>{
const {skip, limit} = getPagination(req.query);
const {searches} = req.query;
if(searches){
posts = await Post.find({title: {$regex: searches.toString(), "$options": "i"}}).populate('username', 'username').sort({createdAt:-1})
.skip(skip)
.limit(limit)
}
}
Now, in Reactjs, I did something like this for pagination query:
useEffect(()=>{
try{
const response = await axios.get(`/posts/?page=${path}`);
}catch(err){
}
}, [path]);
This works for pagination and posts are displayed 12 per page.
Now, in Reactjs, I did something like this for search query:
useEffect(()=>{
try{
const response = await axios.get(`/posts/?searches=${path}`);
}catch(err){
}
}, [path])
Now, this works. It fetch posts based on the search term the user input. The problem is that the result could be way more than I wanted in a page. Is there a way I could integrate the pagination query that I wrote also into this so that when a search result is more than 12, the other posts would be called on the next page?

datatables plugin provides really good pagination out of the box

I sorted this out by passing the search parameter in the body and the pagination on the query. This sorted out my issue. See sample codes
const { skip, limit } = getPagination(req.query); // pagination
const search = req.body.search; // search
if (search) {
posts = await Post.find({ title: { $regex: search.toString(), "$options": "i" } })
.populate('username', 'username').sort({ createdAt: -1 })
.skip(skip)
.limit(limit)
} else {
/* fetch the entire posts if there is no search parameter. */
}

Related

Array.map not returning a value in JavaScript

This is an api endpoint in nextJS that returns the respective authors for an array of posts. The posts is an array of objects that contains a key "authorId". The following code does not work.
const users = posts.map(async (post) => await prisma.user.findUnique({ where: { id: post.authorId }}));
So, I tried the old school way. This thing works
const users = []
for (let i = 0; i < posts.length; i++) {
const user = await prisma.user.findUnique({
where: {
id: posts[i].authorId,
},
});
users.push(user);
}
I thought that the arrow syntax or the implicit return is the issue. So, I tried like this:
const getUsers = async (post: Post) => {
const user = await prisma.user.findUnique({
where: {
id: post.authorId,
},
});
console.log(user);
return user;
};
const users = posts.map(getUsers);
The user object is being logged to the console but its not returning the value (the users is an array of empty objects of times the size of the posts array). Can anyone say where I am doing it wrong?
Note that I'm using prisma as an ORM
Your two code fragments are not equivalent.
getUsers is an async function, so it returns a Promise, that resolves with a user. So, in your last example, the users variable contain an array of promises. What you probably want to do is:
const users = await Promise.all(posts.map(getUsers));
To concurrently get all users from the array of promises.

Query while iterating on array

I have Announcements and AnnouncementLikes schema. There is one schema for announcements and other one is for if user liked the specific announcement. My plan is sending announcements with like state to the user that made a request.
So on the below I tried to get like while iterating on announcement list.
const announcements = await AnnouncementModel.paginate(
{},
{
page,
limit,
lean: true
}
)
announcements.docs = announcements.docs.map((annonucement) => ({
...annonucement,
like: (async () => {
const result = await AnnouncementModel.findIfUserLiked(
annonucement.id,
req.userId
)
return result
})()
}))
It is inside of AnnouncementSchema I didnt want to copy all of the schema
static async findIfUserLiked(announcementId: string, userId: string) {
const foundAnnouncementLike = await AnnonucementLikeModel.findOne({
announcementId,
userId
})
return !!foundAnnouncementLike
}
I know that I cant get likes from immediatly invoked function because it returns a promise. So I have to stop iterate somehow and get like before sending to user. So i tried this solution but it didnt work as well
const fullOfPromises = announcements.docs.map((announcement) => announcement.like)
Promise.all(fullOfPromises).then(() => {
res.send(announcements)
})
I am new to mongoose and I dont know how to get user likes in the announcement list.
Thanks in advance

Github user finder api, how to return multiple users per search? JS

Hello I am using github api to create github user finder. my question is how to manipulate on api link to get users which include e.target.value of the searchbar and not only that one that exactly matches.
here is my code
const [finalData, setFinalData] = useState([]);
const handleSearch = async (e) => {
try {
const URL = `https://api.github.com/users/${e.target.value}?
client_id=e25d1dbedde5215999ef&client_secret=ee080580b7c4f19688ccaef6844c3fe88bb811d`;
Promise.all([fetch(URL).then((res) => res.json())]).then((data) => {
if (data) {
setData(data);
}
});
} catch (err) {
console.log(err);
}
};
const setData = (data) => {
data && setFinalData(data);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
You can use the Search users endpoint. There is a query parameter (q) that allows you to use multiple search criteria documented here
Here's an example using Octokit, but if you still want to use fetch, the endpoint should be https://api.github.com/search/users
Note: I really hope the client secret you are exposing here is for a test application.
Search GitHub users                                                                                
View in Fusebit
const userSearch = ''; // Specify the search text here
const usersResponse = await octokit.rest.search.users({
q: userSearch,
per_page:100
});
const { total_count, items } = usersResponse.data;
console.log(`Listing ${items.length} users of ${total_count} \n`, items.map(user => user.login));

Error while deleting a value of element in mongoDB array using filter function?

I tried to find the solutions over here but unable to get success while using $pull as the array values I have does not contain `mongo_id'.
So the scenario is that , I am trying to delete the specific comment of the particular user which I am passing through query params. M
My mongo data looks like this:
Now I am making API Delete request like this : http://localhost:8000/api/articles/learn-react/delete-comment?q=1 on my localhost .
ANd finally my code looks like this:
import express from "express";
import bodyParser from "body-parser";
import { MongoClient } from "MongoDB";
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect(
"mongodb://localhost:27017",
{ useNewUrlParser: true },
{ useUnifiedTopology: true }
);
const db = client.db("my-blog");
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: "Error connecting to db", error });
}
};
app.delete("/api/articles/:name/delete-comment", (req, res) => {
const articleName = req.params.name;
const commentIndex = req.query.q;
withDB(async(db) => {
try{
const articleInfo = await db.collection('articles').findOne({name:articleName});
let articleAllComment = articleInfo.comments;
console.log("before =",articleAllComment)
const commentToBeDeleted = articleInfo.comments[commentIndex];
//console.log(commentToBeDeleted)
// articleAllComment.update({
// $pull: { 'comments':{username: commentToBeDeleted.username }}
// });
articleAllComment = articleAllComment.filter( (item) => item != commentToBeDeleted );
await articleAllComment.save();
console.log("after - ",articleAllComment);
//yaha per index chahiye per kaise milega pta nhi?
//articleInfo.comments = gives artcle comment
res.status(200).send(articleAllComment);
}
catch(err)
{
res.status(500).send("Error occurred")
}
},res);
});
I have used the filter function but it is not showing any error in terminal but also getting 500 status at postman.
Unable to figure out the error?
I believe you'll find a good answer here:
https://stackoverflow.com/a/4588909/9951599
Something to consider...
You can use MongoDB's built-in projection methods to simplify your code.
https://docs.mongodb.com/manual/reference/operator/projection/positional/#mongodb-projection-proj.-
By assigning a "unique ID" to each of your comments, you can find/modify the comment quickly using an update command instead of pulling out the comment by order in the array. This is more efficient, and much simpler. Plus, multiple read/writes at once won't interfere with this logic during busy times, ensuring that you're always deleting the right comment.
Solution #1: The recommended way, with atomic operators
Here is how you can let MongoDB pull it for you if you give each of your comments an ID.
await db.collection('articles').updateOne({ name:articleName },
{
$pull:{ "comments.id":commentID }
});
// Or
await db.collection('articles').updateOne({ name:articleName, "comments.id":commentID },
{
$unset:{ "comments.$":0 }
});
Solution #2 - Not recommended
Alternatively, you could remove it by index:
// I'm using "3" here staticly, put the index of your comment there instead.
db.collection('articles').updateOne({ name:articleName }, {
$unset : { "comments.3":0 }
})
I do not know why your filter is erroring, but I would recommend bypassing the filter altogether and try to utilize MongoDB's atomic system for you.

which way of fetching data from Graphql server is better?

I have an application with React as client framework and Graphql for running the API.
Plan is fetching user posts and posts count.
Client side
const Profile = () => (
<div>
<PostCount />
<Posts />
</div>
)
const PostCount = () => ...
const Posts = () => ...
We need to display posts in Posts component and the posts count in Count component.
So my question is, which is better.
fetch all of data in Profile component in one request and send it to Post and Count component as props. or fetch posts count in Count component and posts in Post component.
scenario one includes one request to server and bigger chunk of data.
scenario two includes two request to server and smaller chunk of data.
Scenario one server side:
const schema = `
type Query {
feeds(): Feed!
}
type Feed {
posts: [Post!]!
count: Int!
}
type Post {
...
}
`
async function feed() {
const posts: await Post.findAll();
const count = await Post.count();
return {
count
posts,
}
}
Scenario two server side:
const schema = `
type Query {
posts(): [Post!]!
count(): Int!
}
type Post {
...
}
`
async function feed() {
const posts: await Post.findAll();
return posts;
}
async function count() {
const count = await Post.count();
return count;
}
P.S. also consider bigger data. posts and counts are example. for example user posts and user comments.
Both ways are correct! it depends on your application to choose a better approach!
count is usually faster than fetching data ( someone might mess it up!:D), so if you fetch it separately, you can show it faster while your posts are still in loading.
BTW, GQL handles Promise by itself! so there's no need for that async awaits!

Categories