React find and get elements on object array - javascript

In my project I have a state object called products.
{
"productName": "flute",
"batches": [{
"_id": {...},
"batchNo": "flu1",
"expDate": "10/2020",
}, {
"_id": {...},
"batchNo": "flu2",
"expDate": "11/2020",
}],
}
mongoose schema of it is
productName:{
type:String
},
batches:[{
batchNo:{
type:String
},
expDate:{
type:String
},
}]
inside the batches array i want to get data only from a specific batch ID(this.props.batchID)
I tried below code but didn't work.
how can I approach it????
getBatchdetails(){
this.state.products.batches.map(function(object,i){
console.log(object.batchNo);
if(object._id==this.props.obj.batchID){
console.log(object.batchNo);
return object.batchNo;
}
});
}
render() {
return (
<tr>
<td>
{this.state.products.productName}
</td>
<td>
{this.getBatchdetails}
</td>
</tr>
)
}

You can use .find() for that purpose. I made up a fake batchID but you can change to your value.
Try the following:
const batchID = 'id002';
const products = {
"productName": "flute",
"batches": [{
"_id": 'id001',
"batchNo": "flu1",
"expDate": "10/2020",
}, {
"_id": 'id002',
"batchNo": "flu2",
"expDate": "11/2020",
}],
};
const result = products.batches.find(e => e._id === batchID);
console.log(result);
console.log(result.batchNo); // or you can return a specific property
I hope this helps!

Related

Mongoose - How to push object in nested array of objects

I have this data structure in my MongoDB database:
"menu": [
{
"dishCategory":"61e6089f209b802518e2b4a4",
"dishMeals": [
{
"dishMealName": "Burger King",
"dishMealIngredients": "Burger lepinja, bbq sos, berlin sos, zelena"
"dishMealPrice": 5
}
]
}
]
How do I push a new object inside dishMeals in exact dishCategory ( I am providing dishCategoryId, newDish object and _id of restaurant through req.body) I've tried this but nothing is changing:
await Restaurants.updateOne(
{
'_id' : _id,
'menu.dishCategory' : dishCategoryId
},
{
$push : {
'menu.$.dishMeals' : newDish
}
}
);
Use arrayFilters to filter the nested document(s) in the array field, then $push if the filter criteria in the arrayFilters met.
db.collection.update({
"_id": _id,
"menu.dishCategory": dishCategoryId
},
{
$push: {
"menu.$[menu].dishMeals": newDish
}
},
{
arrayFilters: [
{
"menu.dishCategory": dishCategoryId
}
]
})
Sample Mongo Playground
You can do it with arrayFilters config in update query:
db.collection.update({
"restaurant_id": 1
},
{
"$push": {
"menu.$[element].dishMeals": {
"dishMealName": "Best Burger",
"dishMealIngredients": "Best burger in town",
"dishMealPrice": 10
}
}
},
{
"arrayFilters": [
{
"element.dishCategory._id": "61e6089f209b802518e2b4a4"
}
]
})
Working example
You may read the question and the solution they provided here, Hope this one will be helpful to you.
db.collection.update({
"_id": 1,
"menu.dishCategory": "61e6089f209b802518e2b4a4"
},
{
$push: {
"menu.$.dishMeals": newMeal
}
})
Sample Example

Vue-js call object with special id

I'm a newbie in Vue-js and really need your help:
In my Django project I have 2 models: Patient and MedCard of this patient. They are connected with a Foreign Key. I want to implement such functionality: on page "Patients" I have list of patients, then when I push on someone's name I want to see his/her MedCard.
This is my code, but when I push on name I get all records for all patients from MedCard model:
Patients.vue:
<div v-for="patient in patients">
<h3 #click="openMedCard(patient.id)">{{patient.surname}} {{patient.name}}</h3>
<p>{{patient.birth_date}}</p>
</div>
<div
<MedCard v-if="med_record.show" :id="med_record.id"></MedCard>
</div>
export default {
name: 'Patient',
components: {
MedCard,
},
data() {
return {
patients: '',
med_record: {
patient: '',
show: false,
}
}
}
and methods from Patient.vue:
methods: {
openMedCard(id) {
this.med_record.patient = id
this.med_record.show = true
}
MedCard.vue:
<template>
<mu-row v-for="med_record in med_records">
<h3>Doc – {{med_record.doc.surname}}{{med_record.doc.name}}</h3>
<p>{{med_record.patient.surname}}</p>
<p>{{med_record.record}}</p>
<small>{{med_record.date}}</small>
</mu-row>
</template>
export default {
name: 'MedCard',
props: {
id: '',
},
data() {
return {
med_records: '',
}
},
methods: {
loadMedCard() {
$.ajax({
url: "http://127.0.0.1:8000/api/v1/hospital/med_card/",
type: "GET",
data: {
id: this.id,
patient: this.patient
},
success: (response) => {
this.med_records = response.data.data
}
})
}
}
}
loadMedCard() gives me info from all MedCards in JSON like this:
{
"data": {
"data": [
{
"id": 1,
"patient": {
"id": 1,
"surname": "KKK",
"name": "KKK",
"patronymic": "LLL",
"birth_date": "1999-07-07",
"sex": "F",
"phone": "no_phone",
"email": "no_email"
},
"doc": {
"id": 3,
"surname": "DDD",
"name": "DDD",
"patronymic": "DDD",
"education": "d",
"category": "2",
"sex": "m",
"phone": "no_phone",
"email": "no_email"
},
"record": "test text",
"date": "2020-06-09"
}...]
I'll be grateful for any help!
So the API returns you multiple patients's data while you're asking it for just one exact patient. There must be something wrong with the API with the filtering in first place. So you can filter your data on the client side, in your MedCard.vue component. First this component have to show data for one patient only, so the v-for="med_record in med_records" is not needed. Your med_records property can become just an object not an array:
data() {
return {
med_record: {},
}
}
And in the success resolve method of your API call you can filter only the data you need and store it in med_record
success: (response) => {
this.med_records = response.data.data.find((patient)=> { return patient.id === this.id})
}
If you want to store all the data in the med_records, then you can create computed property and apply the same filtering there.
I hope this helps.

How can I format an excel file with empty rows to have nested arrays and match a JSON object that I need to render?

I am facing an issue with an excel file. I receive some data from the DB and the user should be able to replace that data with a spreadsheet that looks like this:
This is how the data comes from the DB and how the excel file should be finally formatted:
"employers": [{
"id": "4147199311345513",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}, {
"id": "3763171269270198",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}]
So I need to take that spreadsheet and format it to look like that JSON above. All of this with Javascript/React.
This is what I have so far to format my excel file and render it:
const [excelData, setExcelData] = useState({ rows: [], fileName: "" });
const fileHandler = (event) => {
let fileObj = event.target.files[0];
ExcelRenderer(fileObj, (err, resp) => {
if (err) {
console.log(err);
} else {
let newRows = [];
let shiftRows = [];
console.log(resp.rows);
resp.rows.slice(1).map((row, index) => {
if (row && row !== "undefined") {
return newRows.push({
key: index,
employer: {
name: row[0],
description: row[1],
employerUrl: row[2],
employerUrlText: row[3],
shifts: shiftRows.push({ shift: row[2] }),
},
});
}
return false;
});
setExcelData({ rows: newRows, fileName: fileObj.name });
}
});
};
That console.log above (console.log(resp.rows)) returns this:
Where the first row are the headers of the excel file.
And the code above ends up like this and it should be exactly as the JSON I mentioned:
rows: [
{
key: 0,
employer: {
name: 'AT&T',
description: 'AT&T is a world premier employer with a bunch of stuff here and there.',
shifts: 1
}
},
{
key: 1,
employer: {
shifts: 2
}
},
{
key: 2,
employer: {
shifts: 3
}
},
{
key: 3,
employer: {
shifts: 4
}
},
{
key: 4,
employer: {
name: 'Verizon',
description: 'Verizon is a world premier employer with a bunch of stuff here and there.',
shifts: 5
}
},
{
key: 5,
employer: {
shifts: 6
}
},
{
key: 6,
employer: {
shifts: 7
}
},
{
key: 7,
employer: {
shifts: 8
}
}
],
fileName: 'EmployerChats.xlsx',
false: {
rows: [
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/0/link.png',
description: 'This is some text'
},
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/1/link.png',
description: 'This is some text'
}
]
},
I am using this plugin to help me render the excel file: https://www.npmjs.com/package/react-excel-renderer
Any ideas on what can I do to make format the spreadsheet data as the JSON?
Please notice those empty rows.
For example every time there is a new employer name, that's a new row or item in the array, then all of the columns and rows below and after Shift Name is a new nested array of objects. Hence, this file contains an array with a length of 2 and then it contains another array of items when it hits the Shift Name column.
Is it clear?
1st of all - you don't need to follow 'original', class based setState. In FC you can just use two separate useState.
const [rows, setRows] = useState([]);
const [fileName, setFileName] = useState("");
Data conversion
I know that you need a bit different workflow, but this can be usefull (common point - data structure), too - as conversion guide, read on.
You don't need to use ExcelRenderer to operate on data from db and render it as sheet. Converted data can be exported to file later.
You can just create array of array (aoa) that follows expected view (rows = array of row cells array). To do this you need very easy algorithm:
let newData = []
map over emplyers, for each (emp):
set flag let first = true;
map over shifts, for each (shift):
if( first ) { newData.push( [emp.name, emp.descr, shift.name, shift.timezone...]); first = false;
} else newData.push( [null, null, shift.name, shift.timezone...]);
setRows( newData );
Rendering
<OutTable/> operates on data and colums props - structures similar to internal state. 'datais ourrows, we only needcolumns` prop, just another state value:
const [columns, setColumns] = useState([
{ name: "Employer name", key: 0 },
{ name: "Employer description", key: 1 },
{ name: "Shift name", key: 2 },
// ...
]);
and finally we can render it
return (
<OutTable data={rows] columns />
Later
User can operate on sheet view - f.e. insert rows using setRows() or download this as file (XLSX.writeFile()) after simple conversion:
var ws = XLSX.utils.aoa_to_sheet( columns.concat( rows ) );
There is a lot of utils you can use for conversions - see samples.
Back to your needs
We have data loaded from db, data in aoa form, rendered as sheet. I don't fully understand format you need, but for your db format conversion is simple (opposite to above) - you can follow it and adjust to your needs.
let newEmployers = [];
let empCounter = -1;
// itarate on rows, on each (`row`):
rows.map( (row) => {
// new employer
if( row[0] ) {
newEmployers.push( {
// id should be here
"employerName": row[0],
"employerDescription": row[1],
"shifts": [
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
]
} );
empCounter ++;
} else {
// new shift for current employer
newEmployers[empCounter].shifts.push(
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
);
}
});
// newEmployers can be sent to backend (as json) to update DB

React mapping menu from JSON

I have a scrolling menu items, and the titles of each item is hardcoded into a const, along side with the id
const list = [
{ name: "category1", id: 0 },
{ name: "category2", id: 1 },
{ name: "category3", id: 2 },
{ name: "category4", id: 3 },
{ name: "category5", id: 4 },
{ name: "category6", id: 5 },
{ name: "category7", id: 6 },
{ name: "category8", id: 7 }
];
I have a json file that contains the category name for each child:
{
"results": [
{
"category": "category1",
"name": {
"title": "mr",
"first": "ernesto",
"last": "roman"
},
"email": "ernesto.roman#example.com",
"id": {
"name": "DNI",
"value": "73164596-W"
},
"picture": {
"large": "https://randomuser.me/api/portraits/men/73.jpg",
"medium": "https://randomuser.me/api/portraits/med/men/73.jpg",
"thumbnail": "https://randomuser.me/api/portraits/thumb/men/73.jpg"
}
},
{
"category": "category2",
"name": {
"title": "mr",
"first": "adalbert",
"last": "bausch"
},
"email": "adalbert.bausch#example.com",
"id": {
"name": "",
"value": null
} etc....
I want to show these categories "category": "category1", as the titles of my menu, I now that I need to start stateless and add them from the JSON, the fetching part from the JSON is done locally in componentDidMount, but I am not sure how can I map them into appearing as menu names to make the menu dynamic, I basically want the same output but from the json not hardcoded. here is a sandbox snippet, would appreciate the help.
https://codesandbox.io/s/2prw4j729p?fontsize=14&moduleview=1
Just convert the JSON output to an object like list with a map function from the results and then set is as MenuItems on the state, which is what you pass to the function on render(). Like that.
import React, { Component } from "react";
import ScrollMenu from "react-horizontal-scrolling-menu";
import "./menu.css";
// One item component
// selected prop will be passed
const MenuItem = ({ text, selected }) => {
return (
<div>
<div className="menu-item">{text}</div>
</div>
);
};
// All items component
// Important! add unique key
export const Menu = list =>
list.map(el => {
const { name, id } = el;
return <MenuItem text={name} key={id} />;
});
const Arrow = ({ text, className }) => {
return <div className={className}>{text}</div>;
};
export class Menucat extends Component {
state = {
selected: "0",
MenuItems: []
};
componentDidMount() {
fetch("menu.json")
.then(res => res.json())
.then(result => {
const items = result.results.map((el, idx) => {
return { name: el.category, id: idx };
});
this.setState({
isLoaded: true,
MenuItems: items
});
});
}
render() {
const { selected, MenuItems } = this.state;
// Create menu from items
const menu = Menu(MenuItems, selected);
return (
<div className="App">
<ScrollMenu
data={menu}
selected={selected}
onSelect={this.onSelect}
alignCenter={true}
tabindex="0"
/>
</div>
);
}
}
export default Menucat;
Cheers!
Looks like you don't have to hard code your category list at all. In your componentDidMount() fetch the json and group the results into separate categories like this:
const json = {
"results": [
{
category: "category1",
name: "Fred"
},
{
category: "category1",
name: "Teddy"
},
{
category: "category2",
name: "Gilbert"
},
{
category: "category3",
name: "Foxy"
},
]
}
const grouped = json.results.reduce((acc, cur) => {
if (!acc.hasOwnProperty(cur.category)) {
acc[cur.category] = []
}
acc[cur.category].push(cur)
return acc;
}, { })
// parent object now has 3 properties, namely category1, category2 and category3
console.log(JSON.stringify(grouped, null, 4))
// each of these properties is an array of bjects of same category
console.log(JSON.stringify(grouped.category1, null, 4))
console.log(JSON.stringify(grouped.category2, null, 4))
console.log(JSON.stringify(grouped.category3, null, 4))
Note that this json has 4 objects in result array, 2 of cat1, and 1 of cat 2 and cat3. You can run this code in a separate file to see how it works. Ofcourse you will be fetching the json object from server. I just set it for demonstration.
Then set teh state:
this.setState({ grouped })
Then in render() you only show the categories that have items like:
const menuBarButtons = Object.keys(this.state.grouped).map((category) => {
/* your jsx here */
return <MenuItem text={category} key={category} onClick={this.onClick} blah={blah}/>
/* or something , it's up to you */
})
I'm assuming you're showing the items based on the currently selected category this.state.selected. So after you have rendered your menu, you would do something like:
const selectedCatItems = this.state.grouped[this.state.selected].map((item) => {
return <YourItem name={item.name} key={item.id} blah={blah} />
})
Then render it:
return (
<div className="app">
<MenuBar blah={blah}>
{menuBarButtons}
</Menubar>
<div for your item showing area>
{selectedCatItems}
</div>
</div>
)
Also, don't forget to change your onClick() so that it sets this.state.selected state properly. I believe you can figure that out yourself.
Hope it helps.
PS: I didn't write a whole copy/paste solution to your problem simply because I'm reluctant to read and understand your UI details and the whole component to component data passing details..

Manipulating MongoDB response NodeJS

I made a "little" query for mongodb to join two collections and retrieve data.
The game: insert 2 or 3 params on a URL
-include can be 0,1 or 2.
0 exclusive
1 inclusive
2 return all
-netcode: is a key to filter data
-group: another optional keys, that works with the first param "include"
-My query works perfectly, returns in a way how much times a event happened in a certain group.
-The problem? I can't work with the result of mongo db, i need to parse it to JSON.
I'm not so clever at JS, so i don't know where to put it. Since i work in corporation, some of the code was already done.
Well my output is this:
{
"events": [
{
"_id": {
"group": "GFS-CAJEROS-INFINITUM-TELDAT-M1",
"event": "SNMP DOWN"
},
"incidencias": 1
},
{
"_id": {
"group": "GFS-CAJEROS-MPLS",
"event": "Proactive Interface Input Utilisation"
},
"incidencias": 1209
},
{
"_id": {
"group": "GFS-CAJEROS-MPLS",
"event": "Proactive Interface Output Utilisation"
},
"incidencias": 1209
},
{
"_id": {
"group": "GFS-CAJEROS-MPLS",
"event": "Proactive Interface Availability"
},
"incidencias": 2199
},
{
"_id": {
"group": "GFS-SUCURSALES-HIBRIDAS",
"event": "Proactive Interface Output Utilisation"
},
"incidencias": 10
},
But i want it fused in a JSON format, like this: check the int value is next for the name of the event.
[
{
"group": "GFS-CAJEROS-MPLS",
"Proactive Interface Input Utilisation" : "1209",
"Proactive Interface Output Utilisation" : "1209",
"Proactive Interface Availability" : "2199",
},
{
"group": "GFS-SUCURSALES-HIBRIDAS",
"Proactive Interface Output Utilisation" : "10",
},
I'm using Nodejs and the mongodb module, since i dont know how this function exactly works, i don't know how to manage the response, ¿there is a better way to do this? like to get the json file, using another js to generate it?
This is the code i'm using, basically is the important part:
var events = db.collection('events');
events.aggregate([
{ $match : { netcode : data.params.netcode } },
{
$lookup:
{
from: "nodes",
localField: "name",
foreignField: "name",
as: "event_joined"
}
},
{ $unwind: {path: "$event_joined"} },
{ $match : {"event_joined.group" :
{$in:
[
groups[0] ,
groups[1] ,
groups[2] ,
groups[3] ,
groups[4] ,
groups[5] ,
groups[6] ,
groups[7] ,
groups[8] ,
groups[9] ,
]
}
}
},
{ $group : { _id : {group:"$event_joined.group", event:"$event"}, incidencias: { $sum: 1} } },
])
.toArray( function(err, result) {
if (err) {
console.log(err);
} else if (result) {
data.response.events = result;
} else {
console.log("No result");
}
You should add another $group to your pipeline {_id: "$_id.group", events: {$push : {name: "$_id.event", incidencias: "$incidencias"}}}
Then change the structure of your data on the JS code with "Array.map".
data.response.events = data.response.events.map(function (eve){
var obj = {
"group": eve.group
};
eve.events.forEach(function (e){
obj[e.name] = e.incidencias
})
return obj;
})

Categories