Search for Specific Records in Mongo DB - node.js

I am trying to fetch data from my course model where I have some data related to courses from MongoDB database. I want to implement a search mechanism so that only those documents should be fetched which are typed in the search bar.
Following is the server side code :
I am successful getting the key but unable to get valid records. Everytime I perform search operation I get all the records. Please Help.
export const searchCourses = async (req, res) => {
try {
console.log('SEARCH COURSES ==>');
const { key } = req.params;
console.log(key)
const courses = await Course.find({
$or: [
{
title: { $regex: key, $options: 'i'}
},
{
description:{
$regex: key, $options:'$i'
}
}
]
},
)
.populate('instructor', '_id name')
.exec()
console.log(courses)
res.json(courses)
} catch (err) {
console.log(err);
res.sendStatus(404);
}
};

I don't understand the question 100%, but to my understanding you are trying to filter results by a text input from the user? In that case you should use a useState, and send that to the server as a query. Here is a short example:
Client code:
const Context = React.createContect({
async listData(query) {
return await fetch("/api/search?" + new URLSearchParams(query));
};
});
function SearchData(){
const {listData} = useContext(Context);
const [data, setData] = useState();
const [dataQuery, setDataQuery] = useState();
const { res } = async () => listGroups({ data }), [data]);
<input onChange={(e) => setDataQuery(e.target.value)} />
<button onClick={() => setData(dataQuery)} />
}
And server code:
router.get("/api/search", async (req, res) => {
const [ data ] = req.query;
const filter = {};
if(data){
filter.data = {$in: [data]};
}
const db = await database.collection(collection).find(filter)
.map(({info} => ({info}))
.toArray()
res.json(db);
});
Not sure if this code exactly will work, but most of the functions are copied from own code, which works.

Related

My Chat List in isnt ordered according to newest chat

I am new to websockets and socket.io. I have a few challenges>
I have developed the application with react and nodejs using socket.io.
useEffect(() => {
const getAllChats = async (token) => {
try {
setLoading(true)
const res = await getChats(token)
if (res) {
setChats(res)
setLoading(false)
}
} catch (err) {
console.log(err)
setLoading(false)
}
}
getAllChats(user.token)
}, [])
export const getChats = (token) => {
return request(`/api/v1/chats`, {
token,
method: 'GET',
})
}
The above code is used to fetch the chat from the backend.
At the backend, I have the code:
exports.getAllChats = catchAsync(async (req, res, next) => {
const user = await Chat.findOne({ user: req.user._id }).populate(
'chats.messagesWith'
)
let chatsToBeSent = []
if (user.chats.length > 0) {
chatsToBeSent = await user.chats.map((chat) => ({
messagesWith: chat.messagesWith._id,
firstName: chat.messagesWith.firstName,
lastName: chat.messagesWith.lastName,
profilePicUrl: chat.messagesWith.profilePicUrl,
lastMessage: chat.messages[chat.messages.length - 1].msg,
date: chat.messages[chat.messages.length - 1].date,
}))
}
return res.json(chatsToBeSent)
})
How can I make new messages remain at the top of the list? Presently, It is always ordered by created date

star rating value from React to Mongodb

I am working to show the rating for every college that is shown to user based on user score. Suppose user A gives college 1 as rating 5, then the rating will be send to mongodb database
In database I have made a collection named rating
ratingSchema = mongoose.Schema({
rating: Number,
userId: {
ref: 'users',
type: mongoose.SchemaTypes.ObjectId
// a string or whatever your id is
},
collegeId: {
ref: 'colleges',
type: mongoose.SchemaTypes.ObjectId
},
})
const Rating = mongoose.model('rating', ratingSchema);
The query written in nodeJS file is:
Rating
.findOne({})
.populate('userId')
.populate('collegeId');
How to post the rating from react to mongodb.
the function made in react is :
component/Report.js
const StarRating = (props) => {
console.log(props);
return (
<div>
{Array(5)
.fill(0)
.map((_, idx) => (
<label key={idx}>
<input
type="radio"
name="rating"
onChange={handleRate}
value={props.ratingValue}
checked={idx === props.ratingValue}
/>
<FaStar color={idx < 3 ? "#01af93" : "#bbb"} />
</label>
))}
</div>
);
};
const Report = (props) => {
const { advices } = useSelector((state) => state.advice);
const [rate, setRating] = useState(null);
useEffect(() => {
if (!advices) {
dispatch(fetchAdvices(history));
}
});
useEffect(() => {
async function fetchRate() {
try {
const { rating } = await api.get(paths.FETCH_RATING);
console.log(rating + "user rating");
} catch(error) {
console.log(error);
}
};
fetchRate();
}, []);
const handleRate = async() => {
const rate = await api.post(paths.UPDATE_RATING, {rating:rate});
props.setRating(rate)
}
return (
<>
<Container>
<Grid>
<Fragment>
<Grid >
<Card>
<CardContent><> <div>
<StarRating setRating={(val) => setRate(val)} ratingValue={rate} />
</div></></CardContent>
</Card>
</Grid>
</>
)};
i want to set rating for college and next time when user sees the order of colleges will be in the highest ranking to lowest ranking.
const router = express.Router();
router.post('/ratings', async (req, res) => {
const { rating, collegeId } = req.body;
// just an example to userId, depends on your authentication method
const userId = req.user.id
// example validation
if (!rating || !collegeId) {
return res.status(400).send({ message: 'bad request.' });
}
try {
const newRating = new Rating({rating, collegeId, userId})
await newRating.save()
return res.status(201).json({message:"success", rating:newRating})
} catch (error) {
res.status(500).send({ message: 'database error' });
}
});
then you can axios.post("yourApiUrl/ratings", {rating: 5, collegeId:123456})
router.get('/ratings', async (req, res) => {
try {
// maybe you need modify I didn't memorize mongoose methods
const ratings = await Rating.find({userId}
.populate('userId')
.populate('collegeId').sort({rating:1});
return res.status(201).json({message:"success", ratings})
} catch (error) {
res.status(500).send({ message: 'database error' });
}
});
this route gives ordered by user ratings.

Showing only Post That user Posted in Reactjs with Server Side is Node Js, Mongodb

What I want?
I want to add post that only login user post. This post only showing My Item component page. here is my all code. When I login and try to add post and then check my item component page. this page showing all of the post. app.get and Server url '/product' it's collect ```email object'''
Thank you.
async function run() {
try {
await client.connect();
const productCollection = client.db("data").collection("product");
app.get("/product", async (req, res) => {
const query = {};
const cursor = productCollection.find(query);
const products = await cursor.toArray();
res.send(products);
});
app.get("/product", async (req, res) => {
const email = req.query.email;
const query = {email: email};
const cursor = productCollection.find(query);
const products = await cursor.toArray();
res.send(products);
});
app.get("/product/:id", async (req, res) => {
const id = req.params.id;
const query = { _id: ObjectId(id) };
const product = await productCollection.findOne(query);
res.send(product);
});
app.post("/product", async (req, res) => {
const newProduct = req.body;
const result = await productCollection.insertOne(newProduct);
res.send(result);
});
// DELETE
app.delete("/product/:id", async (req, res) => {
const id = req.params.id;
const query = { _id: ObjectId(id) };
const result = await productCollection.deleteOne(query);
res.send(result);
});
app.put('/update-quantity/:id', async (req, res) => {
const id = req.params.id;
const updatedInventoryInfo = req.body;
const filter = { _id: ObjectId(id) };
const options = { upsert: true };
const updatedDoc = {
$set: {
quantity: updatedInventoryInfo.quantity,
sold: updatedInventoryInfo.sold
}
}
const result = await productCollection.updateOne(filter, updatedDoc, options);
res.send(result);
})
} finally {
}
}
Client Side Code React Js
import axios from "axios";
import React, { useEffect } from "react";
import { Button, Col, Container, Row } from "react-bootstrap";
import { useAuthState } from "react-firebase-hooks/auth";
import { useNavigate } from "react-router-dom";
import auth from "../../firebase.init";
import useProduct from "../../Hooks/useProduct";
const MyItem = () => {
const [user] = useAuthState(auth);
const [products, setProducts] = useProduct();
const navigate = useNavigate();
useEffect(() => {
const getItems = async () => {
const email = user.email;
console.log(email);
const url = `http://localhost:5000/product?email=${email}`;
const { data } = await axios.get(url);
setProducts(data);
};
getItems();
}, [user]);
const handelDelete = (id) => {
const process = window.confirm(
"Are you sure you want to delete this item?"
);
if (process) {
const url = `http://localhost:5000/product/${id}`;
fetch(url, {
method: "DELETE",
})
.then((res) => res.json())
.then((result) => {
console.log(result);
setProducts(products.filter((product) => product._id !== id));
});
}
};
const navigateToProductDetails = (id) => {
navigate(`/product/${id}`);
};
return (
<>
<Container>
<Row>
{products.map((product, index) => {
return (
<Col key={index} md={4}>
<div className="product-aria">
<img src={product.img} alt="" />
<div>
<h1>{product.name}</h1>
<p>Details:{product.content}</p>
<div className="d-flex gap-3 flex-wrap justify-content-center">
<Button
onClick={() => navigateToProductDetails(product._id)}
variant="primary"
>
Manage
</Button>
<Button
onClick={() => handelDelete(product._id)}
variant="danger"
>
Delete
</Button>
</div>
</div>
</div>
</Col>
);
})}
</Row>
</Container>
</>
);
};
export default MyItem;
<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>
Node Js
Your Are using same api url /products. So I Change this url and its work fine now.
app.get("/products", async (req, res) => {
const query = {};
const cursor = productCollection.find(query);
const products = await cursor.toArray();
res.send(products);
});
app.get("/product", async (req, res) => {
const email = req.query.email;
const query = {email: email};
const cursor = await productCollection.find(query).toArray();
res.send(cursor);
});
app.get("/product/:id", async (req, res) => {
const id = req.params.id;
const query = { _id: ObjectId(id) };
const product = await productCollection.findOne(query);
res.send(product);
});
app.post("/products", async (req, res) => {
const newProduct = req.body;
const result = await productCollection.insertOne(newProduct);
res.send(result);
});
I think you are using a custom hook. useProduct() I just comment it and use useState() hook and change the dependancy useEffect hook user to email. Here is my code.
const [user] = useAuthState(auth);
const { email } = user;
console.log(email);
// const [products, setProducts] = useProduct();
const [products, setProducts] = useState([]);
const navigate = useNavigate();
useEffect(() => {
const getItems = async () => {
// console.log(email);
const url = `http://localhost:5000/product?email=${email}`;
const { data } = await axios.get(url);
setProducts(data);
};
getItems();
}, [email]);

How to populate join table Objection.js

In learning how to use Objection.js, I am interested in learning how to implement a join table and populate it with the associated foreign keys. I made some progress but I'm not sure I am setting things up correctly. I created a smaller side project from my main project that is simplified so I can test without all the extra noise from the code I do not need to troubleshoot. So far, I can set this ORM up fine with no errors. Now I am interested in utilizing join tables and turn to the StackOverflow Community for any feedback I may be given. Going through the documentation, I can see that I would need to make use of the 'extra' property inside my relationMappings() method.
I made sure to create the correct mapping for each model, Actors, Movies and ActorsMovies. I also made sure to create a model for the join table. When I first started testing, I added the 'extra' property to the migration of the 'actors_movies' table as a string, then changed the data type to integer because ultimately, that is how I intend on using it. In order for this to be implemented correctly, do I only need one 'extra' property? Because I added a second 'extra' property named 'author'. So, the two are now 'character' used in the Actor model and 'author' in the Movie model.
Additional pages from Objection that I referenced are the following:
Join Table Recipe and
Ternary relationships Recipe
My small test comes from the examples that were provided in the Objection documentation, so that will be the point of reference I will put here. Three tables: Actors, Movies and ActorsMovies.
const { Model } = require('objection');
const knex = require('../db/dbConfig');
Model.knex(knex);
class Actor extends Model {
static get tableName() {
return 'actors'
}
static get relationMappings() {
const Movie = require('./Movie')
return {
movies: {
relation: Model.ManyToManyRelation,
modelClass: Movie,
join: {
from: 'actors.id',
through: {
from: 'actors_movies.actor_id',
to: 'actors_movies.movie_id',
extra: {
character: 'character'
}
},
to: 'movies.id'
}
}
};
}
}
module.exports = Actor;
//Movies.js
const { Model } = require('objection');
const knex = require('../db/dbConfig');
Model.knex(knex);
class Movie extends Model {
static get tableName() {
return 'movies'
}
static get relationMappings() {
const Actor = require('./Actor')
return {
actors: {
relation: Model.ManyToManyRelation,
modelClass: Actor,
join: {
from: 'movies.id',
through: {
from: 'actors_movies.movie_id',
to: 'actors_movies.actor_id',
extra: {
author: 'author'
}
},
to: 'actors.id'
}
}
};
}
}
module.exports = Movie;
//ActorsMovies.js
const { Model } = require('objection');
const knex = require('../db/dbConfig');
Model.knex(knex);
class ActorsMovies extends Model {
static get tableName() {
return 'actors_movies';
}
static get idColumn() {
return ['actor_id', 'movie_id'];
}
static get relationMappings() {
const Actor = require('./Actor');
const Movie = require('./Movie');
return {
actor: {
relation: Model.BelongsToOneRelation,
modelClass: Actor,
join: {
from: 'actors_movies.actor_id',
to: 'actors.id'
}
},
movie: {
relation: Model.BelongsToOneRelation,
modelClass: Movie,
join: {
from: 'actors_movies.movie_id',
to: 'movies.id'
}
}
};
}
}
module.exports = ActorsMovies;
For this test project, I am interested in making sure the ActorsMovies table gets correctly populated with the actor_id and the movie_id when a movie is created with a POST request.
// api/actors.js
const express = require('express');
const router = express.Router();
const Actors = require('../models/Actor');
const Movies = require('../models/Movie');
/************************/
/********* READ *********/
/************************/
router.get('/', async (req, res, next) => {
try {
const user = await Actors.query();
res.status(200).json(user)
} catch(error) {
console.log(error.message)
}
});
router.get('/:id', async (req, res, next) => {
try {
const actorId = req.params.id;
const actor = await Actors.query().findById(actorId);
const movie = await Actors.relatedQuery('movies')
.for(actor.id)
.insert({ name: actor.name, character: actor.id }).debug()
res.status(200).json(movie)
} catch (error) {
console.log(error.message)
}
});
module.exports = router;
// api/movies.js
const express = require('express');
const router = express.Router();
const Movies = require('../models/Movie');
/************************/
/********* READ *********/
/************************/
router.get('/', async (req, res, next) => {
try {
const movie = await Movies.query();
res.status(200).json(movie)
} catch(error) {
console.log(error.message)
}
});
router.get('/:id', async (req, res, next) => {
try {
const movieId = req.params.id;
const movie = await Movies.query().findById(movieId);
const actor = await Movies.relatedQuery('actors')
.for(movie.id)
.insert({ name: 'The Room', author: movie.id }).debug();
res.status(200).json(actor)
} catch (error) {
console.log(error.message)
}
});
/************************/
/******** CREATE ********/
/************************/
router.post('/', async (req, res, next) => {
try {
const createMovie = req.body;
const newMovie = await Movies.query().insert(createMovie);
const actor = await Movies.relatedQuery('actors')
.for(newMovie.id)
.insert({ name: newMovie.name, author: newMovie.id })
res.status(201).json(actor)
} catch (error) {
console.log(error.message)
}
});
module.exports = router;
//migration file
exports.up = knex => {
return knex.schema
.createTable('actors', table => {
table.increments('id').primary();
table.string('name');
table.timestamps(false, true);
})
.createTable('movies', table => {
table.increments('id').primary();
table.string('name');
table.timestamps(false, true);
})
.createTable('actors_movies', table => {
table.integer('actor_id').references('actors.id');
table.integer('movie_id').references('movies.id');
// The actor's character's name in the movie.
table.integer('character');
table.integer('author');
table.timestamps(false, true);
});
};
exports.down = function(knex) {
return knex.schema
.dropTableIfExists('actors_movies')
.dropTableIfExists('movies')
.dropTableIfExists('actors')
};
// dbConfig.js
require('dotenv').config();
const environment = process.env.NODE_ENV || 'development'
const config = require('../knexfile.js')[environment]
module.exports = require('knex')(config)
The server works fine, the connection between knex.js and Objection.js is fine too. I get a clean response in Postman, but I'm hoping to get an experienced opinion on how I am implementing this. As a side note, I did scour StackOverflow and did not find my specific question, so your feedback will be greatly appreciated.

How to pass users' data from nodeJS to reactJS using Express/Mysql

I need to pass author's email in my posts. I though I can do it by joining tables in my posts route, but it doesn't really work.
Here is my route :
router.get("/posts", async (req, res) => {
const { id } = req.session.user;
//const usersPosts = await user.$relatedQuery("posts");
try {
const user = await User.query().findById(id);
if (!user) {
return res.status(401).send("User was not found");
}
const posts = await Post.query()
.select([
"users.email",
"images.name",
"posts.category",
"posts.title",
"posts.description",
"posts.created_at"
])
.join("images", { "posts.image_id": "images.id" });
.join("users", { "posts.user_email": "users.email" });
console.log("it worked");
return res.status(200).send({ posts: posts });
} catch (error) {
console.log(error);
return res.status(404).send({ response: "No posts found" });
}
});
Here is code with my axios fetching the route :
function Home(props) {
const [posts, setPosts] = useState([]);
const getPosts = async () => {
try {
let response = await axios.get("http://localhost:9090/posts", {
withCredentials: true
});
console.log(response.data.posts);
setPosts(response.data.posts);
} catch (error) {
console.log(error.data);
}
};
useEffect(() => {
getPosts();
}, []);
And this is how I tried to return it:
{posts.map((post, index) => {
return (
<>
Author:<br></br>
<small>{post.user_email}</small>
</p>
<p>
Category:<br></br>
<small>{post.category}</small>
</p>
<p>
Description:<br></br>
<small>{post.description}</small>
</p>
<p>
Created: <br></br>
<small>{post.created_at}</small>
Everything works except the fetching Author.
a typo its user_email not users_email
your sending email in the value assingned to user_email and in front end using users_email

Resources