Searching in mongodb atlas on express - node.js

hi everyone i have data on mongodB atlas this is my mongoose Schema
mongoose Schema
and this is client
client
import React, { useState, useEffect } from 'react';
import { Container, AppBar, Typography, Grow, Grid } from '#material-ui/core';
import { useDispatch } from 'react-redux';
import SearchBar from "material-ui-search-bar";
import Posts from './components/Posts/Posts';
import Form from './components/Form/Form';
import { getPosts } from './actions/posts';
import useStyles from './styles';
import memories from './images/memories.png';
const App = () => {
const [currentId, setCurrentId] = useState(0);
const dispatch = useDispatch();
const classes = useStyles();
useEffect(() => {
dispatch(getPosts());
}, [currentId, dispatch]);
return (
<Container maxWidth="lg" >
<AppBar className={classes.appBar} position="static" color="inherit">
<Typography className={classes.heading} variant="h2" align="center">Search Bar</Typography>
<SearchBar />
</AppBar>
<Grow in>
<Container>
<Grid container justify="space-between" alignItems="stretch" spacing={3}>
<Grid item xs={12} sm={7}>
<Posts setCurrentId={setCurrentId} />
</Grid>
<Grid item xs={12} sm={4} >
<Form currentId={currentId} setCurrentId={setCurrentId} />
</Grid>
</Grid>
</Container>
</Grow>
</Container>
);
};
export default App;
use this https://github.com/TeamWertarbyte/material-ui-search-bar
to Search i try to use "Mongoose Fuzzy Searching Plugin"
i do this Mongoose Fuzzy Searching
import mongoose from 'mongoose';
import mongoose_fuzzy_searching from 'mongoose-fuzzy-searching';
const postSchema = mongoose.Schema({
title: String,
message: String,
creator: String,
tags: [String],
selectedFile: String,
link:String,
createdAt: {
type: Date,
default: new Date(),
},
})
postSchema.plugin(mongoose_fuzzy_searching, { fields: ['message', 'title'] });
var PostMessage = mongoose.model('PostMessage', postSchema);
export default PostMessage;
what i need to write in router? i don't understand...
and how i displays the results in react?
In addition, how i can URL validation?

You have to use the fuzzy search with your backend API just like that
await Product.fuzzySearch(search).find()

export const SearchPost = async (req, res) => {
const search = req.body.search;
try {
const search = await PostMessage.fuzzySearch(search).find();
res.status(200).json(search);
} catch (error) {
res.status(404).json({ message: error.message });
}
}

Related

Not populating mongoDB database with data being entered on angular

I am writing a post form function using MEAN stack which saves the data to the DB.
When entering the data through postman on the node, express, mongoose side it stores in the database. however when entering the date through the angular frontend, the data isnt storing, this method i used for other forms and it worked however this one just doesn't:
HTML:
<form [formGroup]="form" (submit)="addMessage()">
<mat-form-field>
<mat-label>Username:</mat-label>
<input
placeholder="Username"
matInput
formControlName="username"
class="form-control"
type="string"
required
/>
</mat-form-field>
<br />
<mat-form-field>
<mat-label>Message:</mat-label>
<input
placeholder="Type Message Here..."
matInput
formControlName="message"
class="form-control"
type="string"
required
/>
</mat-form-field>
<br />
<mat-form-field>
<mat-label>Message Date:</mat-label>
<input
placeholder="Type Message Here..."
matInput
formControlName="messageDateTime"
class="form-control"
type="date"
required
/>
</mat-form-field>
<br />
<button mat-raised-button color="basic" type="submit">Send</button>
<br />
<mat-divider></mat-divider>
</form>
Typescript:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup } from '#angular/forms';
import { Router } from '#angular/router';
import { MessageBoardService } from 'src/app/service/message-board.service';
import { Message } from 'src/app/models/messages.interface';
#Component({
selector: 'app-message-board',
templateUrl: './message-board.component.html',
styleUrls: ['./message-board.component.css']
})
export class MessageBoardComponent implements OnInit {
messages: Message[] = [];
constructor(private messageService: MessageBoardService) { }
form = new FormGroup({
username: new FormControl(''),
message: new FormControl(''),
messageDateTime: new FormControl(''),
});
addMessage() {
console.log('adding');
const formData = new FormData();
formData.append('username', this.form.value.username);
formData.append('message',this.form.value.message);
formData.append('messageDateTime',this.form.value.messageDateTime);
this.messageService.postMessage(formData).subscribe((d) => {
console.log(d);
});
//window.location.reload();
}
ngOnInit(): void {
this.messageService.getMessage().subscribe((M: Message[]) => {
this.messages = M;
})
}
}
Service:
postMessage(data: any){
return this.http.post<any>("http://localhost:3000/Messages", data)
.pipe(map((res:any)=>{
return res;
}))
}
The get function works fine in the services it is only the post.
Posting data using postman works well, but from the frontend it just saves the default data that is set in the mongoose schema
Schema:
const mongoose = require('mongoose');
const MessagesSchema = new mongoose.Schema({
username:{
type: String,
required: false,
default: "User"
},
message:{
type: String,
required: false,
default:"Content"
},
messageDateTime:{
type: Date,
required: false,
default: Date.now
}
})
const Messages = mongoose.model( 'Messages', MessagesSchema);
module.exports = Messages
Data Entered Using Angular Frontend:
Data Saved in Database:
(Console Output):
{username: 'User', message: 'Content', messageDateTime:
'2022-03-04T23:23:32.040Z', _id: '62229f740a9c53a525774f01', __v: 0}
message: "Content" messageDateTime: "2022-03-04T23:23:32.040Z"
username: "User"
__v: 0
_id: "62229f740a9c53a525774f01" [[Prototype]]: Object
(Data stored accessed by postman):
{
"_id": "62229f740a9c53a525774f01",
"username": "User",
"message": "Content",
"messageDateTime": "2022-03-04T23:23:32.040Z",
"__v": 0
},
I'm not sure why do you need FormData, as I have never used it in Angular
I generally send data like this to backend
let dataToSend: any = {
username: this.form.value.username,
message: this.form.value.message,
messageDateTime: this.form.value.messageDateTime
}
this.messageService.postMessage(dataToSend).subscribe((d) => {
console.log(d);
});
I'll also update the service and Content-Type header, assuming your backend is expecting JSON.
let headers = new Headers();
headers.append('Content-Type', 'application/json');
postMessage(data: any)
{
http.post('http://localhost:3000/Messages', JSON.stringify(data), {
headers : headers
}).pipe('Rest of the Code');
}

Graph won't start at zero

I'm working on a Dashboard, and I'm trying to display daily sales on a graph using mongodb. The issue that I'm having is that my graph does not start at 0, instead it starts at a number closer to the lowest number of daily sales that I entered. Also, the graph only displays the two dates that had sales, and I was wondering if there was a way to include all dates in between and following those dates? I would really appreciate any help or advice on how to solve this problem. Thank you!
OrderRouter.js
import express from 'express';
import expressAsyncHandler from 'express-async-handler';
import Order from '../models/orderModel.js';
import User from '../models/userModel.js';
import Product from '../models/productModel.js';
import {isAdmin, isAuth, isSellerOrAdmin, mailer, payOrderEmailTemplate} from '../utils.js';
orderRouter.get(
'/summary',
isAuth,
isAdmin,
expressAsyncHandler(async (req, res) => {
const dailySales = await Order.aggregate([
{
$group: {
_id: { $dateToString: { format: '%m-%d-%Y', date: '$createdAt' } },
orders: { $sum: 1 },
sales: { $sum: '$totalPrice' },
},
},
{ $sort: { _id: 1 } },
]);
res.send({ dailySales });
})
);
export default orderRouter;
DashboardScreen.js
import { useDispatch, useSelector } from 'react-redux';
import Chart from 'react-google-charts';
import { summaryOrder } from '../actions/orderActions';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
export default function DashboardScreen() {
const orderSummary = useSelector((state) => state.orderSummary);
const { loading, summary, error } = orderSummary;
const dispatch = useDispatch();
useEffect(() => {
dispatch(summaryOrder());
}, [dispatch]);
return (
<div>
<div className="line">
</div>
<div className="background">
<div>
<h1>Dashboard</h1>
</div>
{loading ? (
<LoadingBox />
) : error ? (
<MessageBox variant="danger">{error}</MessageBox>
) : (
<>
<div className="graphs">
<div>
<h2 className="graphname">Daily Sales</h2>
{summary.dailySales.length === 0 ? (
<MessageBox>No Sale</MessageBox>
) : (
<Chart
width="100%"
height="400px"
chartType="AreaChart"
loader={<div>Loading Chart</div>}
data={[
['Date', 'Sales'],
...summary.dailySales.map((x) => [x._id, x.sales]),
]}
></Chart>
)}
</div>
</div>
<div>
</div>
</>
)}
</div>
</div>
);
}
In answer to your first question: in the Documentation for react-google-charts, there is a configuration option called: vAxis.minValue, described as:
Moves the min value of the vertical axis to the specified value; this will be downward in most charts. Ignored if this is set to a value greater than the minimum y-value of the data.
I'm betting this will help you out. In the docs, there's also an example of implementation:
vAxis: {minValue: 0}

fetching data from API in react poll

I want to fetch data from API and show frontend using react but I am getting error from frontend side which is (TypeError: answers.map is not a function ) so how can I solve this error --
MY CODE IS -
import React, { useState, useEffect } from "react";
import Poll from "react-polls";
import { getPolls } from "../helper/coreapicalls";
const MainPoll = () => {
const [polls, setPoll] = useState([]);
const [error, seterror] = useState(false);
// Setting answers to state to reload the component with each vote
const [pollAnswers, setPollAnswers] = useState([]);
useEffect(() => {
loadPoll();
}, []);
const loadPoll = () => {
getPolls().then((data) => {
if (data.error) {
seterror(data.error);
} else {
setPoll(data);
console.log(data);
}
});
};
// Handling user vote
// Increments the votes count of answer when the user votes
const handalchange = () => {
console.log("hello");
};
return (
<div className="">
<div className="container">
<h1 className="blog_heading">Poll's of the Day</h1>
<div className="row">
{polls.map((poll, index) => (
<div className="col-lg-4 col-12" key={index}>
<Poll
question={poll.question}
answers={poll.options.none}
onVote={handalchange}
/>
</div>
))}
</div>
</div>
</div>
);
};
export default MainPoll;
Data which I am getting from API is-
Here I have Question , 3 options how can I show to frontend
Error -
There is two little mistakes in the code that you show us:
the first One you imported import Polls from "./polls"; and you call <Poll noStorage question={poll.question} answers={poll.options} onVote={handleVote}/> just change Poll by Polls.
const [pollAnswers, setPollAnswers] = useState([...answers]); this didn't work because you need to pass a initial value for your state and answer is not yet initialize and accessible. just change useState([...answers]); by useState([]);
UPDATE:
you need to pass an array to answers props .
We can see in your console screenshot that the array of options has "none" as key so
try this : <Poll noStorage question={poll.question} answers={poll.options.none} onVote={handleVote}/> ("none" is a strange key...)
UPDATE
Your data object is not well formated to fit react-polls answers props.
in the npmjs doc of react-polls we can see an example of options and it's an array of object like this:
[
{ option: 'Yes', votes: 8 },
{ option: 'No', votes: 2 }
]
so based on the data console log that you add in your question it should looks like this:
[
{
createdAt: "2020-12-01T21:43:23:21.061Z",
options: {
none: [ { option: 'Yes', votes: 8 },
{ option: 'No', votes: 2 }],
student: ["12345678978945"],
teacher: ["7894567894231"]
},
question: "Are you student ot teacher",
updatedAt: "2020-12-01T21:43:23:21.061Z"
}
]
see a sandBox here working with your code (except getPolls()).
I think the issue come from the API.

How to query a single document from a Mongodb collection with react

I'm trying to build a search bar with a react frontend and node backend, that will let me search a customer ID from a mongoDB collection, then pull all of the data from a single document down from within the collection and display it on my react app.
Currently, I am just trying to get to get the single document bit to work, if this is possible. At the moment, it pulls down the entire collection.
My current Node code:
Search router
const express = require('express');
const app = express();
const tfiPaintCodesRouter = express.Router();
const PaintInfoSchema = require('../models/PaintInfoSchema.js');
tfiPaintCodesRouter.route('/get').get(function (req, res) {
const tfipaintcode = new PaintInfoSchema(req.body);
console.log(req.body)
tfipaintcode.save()
.then(tfipaintcode => {
res.json('Got data!!');
})
.catch(err => {
res.status(400).send("unable to get data");
console.log('CustomerID is required', err.res);
});
});
tfiPaintCodesRouter.route('/').get(function (req, res) {
PaintInfoSchema.find(function (err, tfipaintcodes){
if(err){
console.log('this is an error!', err.res);
}
else {
res.json(tfipaintcodes);
}
});
});
module.exports = tfiPaintCodesRouter;
Mongo schema using mongoose.
const mongoose = require('mongoose')
var uniqueValidator = require('mongoose-unique-validator');
const Schema = mongoose.Schema;
// Create schema
const PaintInfoSchema = new Schema({
customerID: {
required: true,
index: true,
unique: true,
type: String
},
companyName: {
index: true,
type: String
},
curtainCodes: {
index: true,
type: String
},
sinageCodes: {
index: true,
type: String
},
Notes: {
index: true,
type: String
},
Method: {
index: true,
type: String
},
},{
collection: 'tfiPaintCodes'
});
PaintInfoSchema.plugin(uniqueValidator);
module.exports = mongoose.model('PaintInfoSchema', PaintInfoSchema)
My current react code is:
import React from 'react';
import { Form, FormGroup, Input, Container, Row, Col } from 'reactstrap';
import './Search.css'
import axios from 'axios'
class Search extends React.Component {
constructor(props) {
super(props)
this.state = {
searchInfo: []
};
}
handleInputChange = (event) => {
event.preventDefault();
const { value } = event.target;
console.log('Value', value)
this.setState({
query: value
});
this.search(value);
};
search = query => {
axios.get('http://localhost:3001/getData')
.then(res =>{
const searchInfo = (res.data || []).map(obj => ({
company: obj.companyName,
sinage: obj.sinageCodes,
method: obj.Method,
notes: obj.Notes}));
this.setState({ searchInfo });
})
};
componentDidMount() {
this.search("");
}
render() {
return(
<Container>
<Form>
<Row>
<Col md={{ size: 6 ,offset: 3}}>
<FormGroup className="SearchBar">
<Input onChange={this.handleInputChange} type="search" name="search" id="exampleSearch" placeholder="search" />
</FormGroup>
</Col>
</Row>
</Form>
<ul>
{this.state.searchInfo.map(function(searchInfo, index){
return (
<div key={index}>
<h1>NAME: {searchInfo.company}</h1>
<p>{searchInfo.sinage}</p>
<p>{searchInfo.method}</p>
<p>{searchInfo.notes}</p>
</div>
)
}
)}
</ul>
</Container>
);
}
}
export default Search
The code above queries mongodb, then pulls down all of the data stored in my collection, here is an image of the returned data.
Data displayed in frontend
But i want to know if it is possible to just pull down one document in that collection, so it would just display one Name: and then the other 4 bits of data.
I have the data stored in Mlab, here is a screenshot of the documents stored in my collection.
data in mongodb
Is this possible? Thanks!
The best way is to pull only one document from the DB (if you don't need more in your case).
Mongoose, as any other ORM/ODM, gives you those options:
https://mongoosejs.com/docs/api.html#model_Model.findOne
With FindOne you can search for documents but get only one (aka. "the first found") document back.
If you need a fixed number of returned documents, you can use limit(10) to, for example, return only 10 documents.
Though it appears to me that your code-snippets don't show the exact segment where do the query in Mongoose, otherwise we could have shown you what to do in your own example.

Return list item with nested ternary in React.js/JSX

I want my react component to return a list item depending on the type of object array that is fed to it (string array element versus non-string array element). Everything works except for the nested ternary part. The conditions are evaluated correctly, when I do <li>{console.log(listValue2)}</li> instead of <li>{listValue2}</li> , the correct value is logged. But the list item does not appear in the DOM or virtual DOM no matter which code I do. My code is also available at https://github.com/neallred/neallred/tree/master/src/components.
Any ideas?
List.jsx
import React from 'react';
export class List extends React.Component {
render(){
return (
<div>
{this.props.list.map(function(listValue, index){
return (
<div key={index}>
<h3>{listValue.title}</h3>
<p>{listValue.description}</p>
<ul>
{(typeof listValue.highlights === 'object' ?
listValue.highlights.map(function(listValue2, index2){
(typeof listValue.highlights[index2] === 'string' ?
<li>{listValue2}</li>
:
<li>{listValue2.title}</li>
)
})
:
<li>no highlights object/outside of nested conditional</li>
)}
</ul>
</div>
);
})}
</div>
);
}
}
This.props.list structure (FixturesEducation.jsx):
import React from 'react';
import { List } from './List.jsx';
...
const researchAssistant = {
title: 'Research Assistant Work',
description: `Working for Professors...`,
highlights: [
'Ensured research replicability',
'more strings here...',
'Used Stata scripts to conduct quantitative analyses'
]
};
const math = {
title: 'Mathematical Foundation',
description: 'Via several math and economics courses...',
highlights: [
'Game Theory (Econ 478)',
'more strings here...',
'Calculus I (Math 112 equivalent)'
]
};
const economics478 = {
title: 'Game Theory',
highlights: [
'several',
'strings...'
]
};
const economics459 = {
...
};
const economics388 = {
...};
const economics382 = {
...
};
const economics = {
title: 'Economics',
description: 'I learned about...,
highlights: [
economics478,
economics459,
economics388,
economics382
]
};
const politicalScience372 = {
...
};
const politicalScience376 = {
...
};
const politicalScience497r = {
...
};
const politicalScience470 = {
...
};
const politicalScience344 = {
...
};
const politicalScience = {
title: 'Political Science',
description: 'I learned a lot...',
highlights: [
politicalScience470,
politicalScience497r,
politicalScience376,
politicalScience372,
politicalScience344
]
};
const spanish = {
title: 'Spanish Language',
description: 'I obtained my Spanish Language certificate...'
};
const businessMinor = {
title: 'Business Minor',
description: 'I this minor, I learned...'
};
const FixturesEducation = {
title: 'Education',
description: 'I attended ...',
highlights: [
researchAssistant,
math,
economics,
politicalScience,
businessMinor,
spanish
]
};
export { FixturesEducation };
Code calling List component (Education.jsx):
import React from 'react';
import { List } from './List.jsx';
...
import { FixturesEducation } from './FixturesEducation.jsx';
...
export class Education extends React.Component {
render(){
return (
<div className='col-md-10 col-md-offset-1 panel' id='education'>
<h1>{FixturesEducation.title}</h1>
<List list ={FixturesEducation.highlights}/>
</div>
);
}
}

Resources