How to delete item in nested array to pass as react state - reactjs

In a react class called CompanyDashboard have a state called data that is an array 3 of objects, each of those objects has a timeslots key that holds an array of timeslots.
Inside CompanyDashboard I have a functional component called CompanyPanel that takes in the value of one company and renders the timeslots as a list of clicable items.
When i click on any of those items I execute a method called deleteTime from CompanyDashboard that is being passed to CompanyPanel as props, with name and timeslot as arguments.
I want to delete from the state called data the specific timeslot of the specific company, which I am getting in the deleteTime method as arguments.
But i dont know how.
On the stateless functional component I have this:
<span className='pa2 red pointer ma2 bg-white' onClick={() => deleteTime(timeslot, company)}>X</span>
and then in the CompanyDashboard this method:
deleteTime (timeslot, company) {
// here i want to remove the specific timeslot from the spcific company from the state data
// and set it to this new state without that specific item inside that specific company
}
The data state looks like this:
data = [
{
"_id": "5db581e58e11ad1b933e7f42",
"name": "ZANITY",
"times": [
{
"timestamp": 1474607824073,
"dateUTCString": "Sat Sep 03 2016 19:01:09 GMT+0000 (UTC)",
},
{
"timestamp": 1389120349942,
"dateUTCString": "Mon Aug 19 2019 05:43:14 GMT+0000 (UTC)",
},
]
},
{
"_id": "5db581e584de79b380890f75",
"name": "VETRON",
"times": [
{
"timestamp": 1474607824073,
"dateUTCString": "Sat Sep 03 2016 19:01:09 GMT+0000 (UTC)",
},
{
"timestamp": 1389120349942,
"dateUTCString": "Mon Aug 19 2019 05:43:14 GMT+0000 (UTC)",
},
]
},
{
"_id": "5db581e565b82e2b729077e1",
"name": "KOZGENE",
"times": [
{
"timestamp": 1474607824073,
"dateUTCString": "Sat Sep 03 2016 19:01:09 GMT+0000 (UTC)",
},
{
"timestamp": 1389120349942,
"dateUTCString": "Mon Aug 19 2019 05:43:14 GMT+0000 (UTC)",
},
]
}
]```

you should add a unique id to the time stamps objects so they would be more distinguishable and easier to deal with, but for now, we can do:
deleteTime (timeslot, company) {
const newState = state.map(company=>{
company.times.filter(time=>{
return time.timestamp !== timeslot
})
return company
})
this.setState(newState) // or setState(newState) if you are functional
}

I found the answer, thought I think it could be done in a simpler way, in any case it works:
deleteTime (timeslot, name) {
const newState = this.state.data.map(company => {
if (name === company.name) {
let newTimes = company.times.filter(time => {
return time.dateUTCString !== timeslot.dateUTCString
})
company.times = newTimes
return company
}
return company
})
this.setState({data: newState}) // or setState(newState) if you are functional
}

Related

Mongo query Update year depends on the inner document field

Here is my data. I wanted to change year but It should effective to only the first item of the document array
{
"_id": {
"$oid": "62053aa8aa1cfbe8c4e72662"
},
"school": "Test",
"reports": [
{
"year": "2020", // This has to be changed to 2019
"createdAt": {
"$date": "2022-02-10T17:05:25.682Z"
},
"pid": {
"$oid": "620545d5097761628f32365a"
},
"details": {
"end_date": {
"$date": "2020-03-31T00:00:00.000Z" // when end date is prior to July 01 of the $year mentioned.
}
}
}, {
"year": "2020",
"createdAt": {
"$date": "2022-03-14T19:08:38.125Z"
},
"pid": {
"$oid": "622f92b68a408531d4b784de"
},
"details": {
"end_date": {
"$date": "2021-03-31T00:00:00.000Z"
}
}
}
]
}
In the above data, I want to reduce the year to the previous year, if details.end_date is prior to July 01 of the current mentioned year. But It should change only the first item of the embedded array.
For example,
If Year is 2020 and details.end_date is prior to 01-July-2020, then change the year to 2019
If Year is 2020 and details.end_date is after 01-July-2020, then do not change the year
If Year is 2021 and details.end_date is prior to 01-July-2021, then change the year to 2020
If Year is 2021 and details.end_date is after 01-July-2021, then do not change the year
You can do the followings in an aggregation pipeline:
isolate the first elem of the reports array for easier processing using $arrayElemAt
use $cond to derive the year value with $month. Use $toInt and $toString for type conversion
use $concatArrays to append back the processed first Elem back to the reports array. Keep only the "tail" (i.e. without the first elem) using $slice
$merge to update the result back to the collection
db.collection.aggregate([
{
"$addFields": {
"firstElem": {
"$arrayElemAt": [
"$reports",
0
]
}
}
},
{
"$addFields": {
"firstElem.year": {
"$cond": {
"if": {
$lt: [
{
"$month": "$firstElem.end_date"
},
7
]
},
"then": {
"$toString": {
"$subtract": [
{
"$toInt": "$firstElem.year"
},
1
]
}
},
"else": "$firstElem.year"
}
}
}
},
{
"$addFields": {
"reports": {
"$concatArrays": [
[
"$firstElem"
],
{
"$slice": [
"$reports",
1,
{
"$subtract": [
{
"$size": "$reports"
},
1
]
}
]
}
]
}
}
},
{
"$project": {
firstElem: false
}
},
{
"$merge": {
"into": "collection",
"on": "_id",
"whenMatched": "replace"
}
}
])
Here is the Mongo playground for your reference.

How to update array elements in MongoDB instead of creating new one

I have problem with my code. I want to update document, which looks like this:
{
"_id": {
"$oid": "5bf2ad5a0d46b81798232cf9"
},
"manufacturer": "VW",
"model": "Golf ",
"VIN": "WVWZZZ1J212566691",
"doors": 3,
"class": "compact",
"reservations": [
{
"_id": {
"$oid": "5bf2ad5a0d46b81798232cfa"
},
"pick_up_date": {
"$date": "2014-10-13T09:13:00.000Z"
},
"drop_off_date": {
"$date": "2014-10-14T09:13:00.000Z"
},
"user_id": {
"$oid": "5bec00bdfb6fc005dcd5423b"
}
}
],
"createdAt": {
"$date": "2018-11-19T12:32:26.665Z"
},
"updatedAt": {
"$date": "2018-11-19T12:32:26.665Z"
},
"__v": 0
}
I want to add new reservation to array Reservations. My function:
const createReservationForCarId = ({ body , params }, res, next) =>
Carmodel.findById(params.id)
.then(notFound(res))
.then((carmodel) => carmodel ? Object.assign(carmodel, body).save() : null)
.then((carmodel) => carmodel ? carmodel.view(true) : null)
.then(success(res))
.catch(next)
But when I'm trying to update through:
router.put('/:id/reservation',
createReservationForCarId)
Body:
{
"reservations":[
{
"pick_up_date" : "October 13, 2017 11:13:00",
"drop_off_date": "October 14, 2017 11:13:00",
"user_id":"5bec00bdfb6fc005dcd5423b"
}
]
}
Mongo instead of update my old document is creating new one with only one reservation gave in above body.
What should I do to only update existing document, not creating new one?
I suggest you use $push operator of Mongoose which will append your object to the existing array and it will not create a new one.
Check out this link:-
https://github.com/Automattic/mongoose/issues/4338
You can try the findAndModify instead of findById in your code. Check out the syntax here
I haven't used mongoose but they have documentation for array manipulation.
See here:
https://mongoosejs.com/docs/api.html#mongoosearray_MongooseArray-push
Also here is the related mongo doc for array manipulation:
https://docs.mongodb.com/manual/reference/operator/update/push/

How can I group a field in subdocument in MongoDB

I have the following document:
{
"_id": "5a5cae1890254804e3a4655d",
"additional_ingredient": {
"concentration": 40.0,
"formulations": [
"5a1826c664f7fe04afbe9198"
]
}
}
Inside additional_ingredient there is an array field formulations. When I have an array field in the first level of a document I can use $unwind then $lookup to join an external document and the group by this field.
But I cannot do the same with a nested array. What is the best solution for that?
What I expect:
{
"_id": "5a5cae1890254804e3a4655d",
"additional_ingredient": {
"concentration": 40.0,
"formulations": [
{
"_id": "5a1826c664f7fe04afbe9198",
"date_created": "Fri, 24 Nov 2017 14:03:50 GMT",
"date_modified": "Fri, 24 Nov 2017 14:03:50 GMT",
}
]
}
}
I have a problem with grouping. The field name 'additional_ingredient.formulations' cannot contain '.'
This is a part of the query:
{"$unwind": "$additional_ingredient.formulations"},
self.__ADDITIONAL_INGREDIENT_FORMULATION_LOOKUP_QUERY,
{"$unwind": "$additional_ingredient.formulations"},
{"$group": {
"_id": "$_id",
"additional_ingredient.formulations": {"$push": "$additional_ingredient.formulations"},
}},

Local variable is not returning correct value + Async Actions Error

I am using Redux-react.
here is the small code of action :
export function copyYearData(year) {
var listData = [
{
"categories": "Years"
},
{
"options": [
{
"label": 2013,
"value": 2013,
},
{
"label": 2014,
"value": 2014,
},
{
"label": 2015,
"value": 2015
},
{
"label": 2016,
"value": 2016
},
{
"label": 2017,
"value": 2017,
},
{
"label": 2018,
"value": 2018,
},
{
"label": 2019,
"value": 2019
},
{
"label": 2020,
"value": 2020
},
{
"label": 2021,
"value": 2021
}
]
}
];
var copyFrom = '';
var copyTo = '';
listData.map(function (obj) {
if (obj.options) {
obj.options.map(function (item) {
if (item.value == year && year < new Date().getFullYear()) {
copyFrom = year;
}
if (item.value == year && year >= new Date().getFullYear()) {
copyTo = year;
}
})
}
});
if (copyFrom != '' && copyTo != '') {
return {
type: 'COPY_DATA',
payload1: copyFrom,
payload2: copyTo
}
}
};
Please, consider year = 2015 (applicable for less than current year i.e. 2017) and year = 2019 (applicable for greater than current year i.e. 2017)
my reducer name is 'helloReducer'.
when I use console.log(store.getState().helloReducer);
It's current output is Object {copyFrom: "", copyTo: ""}
Expected output will be Object {copyFrom: 2015, copyTo: 2019}
Also I got an error of Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
Since you just want to traverse the array, don't want to return something for each element, so don't use map, use forEach it will not return anything by default, the Use this code:
export function copyYearData() {
let data='';
['1','2','3'].forEach((item)=>{
if(item === '2'){
data = item;
}
})
if(data != ''){
return{
type: 'COPY_DATA',
payload: data,
}
}
};

How to iterate over the following structure in Meteor Spacebars?

I'm trying to group a collection by date in Meteor using Underscore's _.groupBy function.
Here is a sample of the code that outputs:
"Mon Dec 07 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"q9TMi9ZyoRjmddzfY",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-07T00:00:00.000Z",
"start":"2015-12-07T08:00:00.000Z",
"end":"2015-12-07T09:00:00.000Z",
"teachers":[
],
"clients":[
{
"clientId":"M4DDCGWGMzX7bJRHa",
"manual":"true"
}
],
"clientLimit":99
}
],
"Tue Dec 08 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"Jbchuc58zWDyEqnQZ",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T08:30:00.000Z",
"end":"2015-12-08T09:30:00.000Z",
"teachers":[
],
"clients":[
],
"clientLimit":15
},
{
"_id":"EsqygwCCPucGhx9nP",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T09:30:00.000Z",
"end":"2015-12-08T10:30:00.000Z",
"teachers":[
"eLExMRh3TT5eYWpki",
"wxFjH39M9kuBTv4zN"
],
"clients":[
],
"clientLimit":10
}
]
}
The problem is, I'm not really sure how I can output these in the front-end. Do I have to somehow convert it to normal arrays or a cursor? Or is there perhaps another way of grouping a collection by date headings?
I'm looking to output something like the following:
Saturday 21st September
- Item 1
- Item 2
Tuesday 24th September
- Item 3
Thanks for any ideas.
This is how I would do it:
loops.html
{{#each arrayify data}}
{{name}} <br>
<ul>
{{#each value}}
<li>ClientLimit: {{this.clientLimit}}</li>
{{/each}}
</ul>
{{/each}}
loops.js
Template.registerHelper('arrayify',function(obj){
result = [];
for (var key in obj) result.push({name:key,value:obj[key]});
return result;
});
Template.hello.helpers({
data: function() {
return {
"Mon Dec 07 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"q9TMi9ZyoRjmddzfY",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-07T00:00:00.000Z",
"start":"2015-12-07T08:00:00.000Z",
"end":"2015-12-07T09:00:00.000Z",
"teachers":[
],
"clients":[
{
"clientId":"M4DDCGWGMzX7bJRHa",
"manual":"true"
}
],
"clientLimit":99
}
],
"Tue Dec 08 2015 00:00:00 GMT+0000 (GMT)":[
{
"_id":"Jbchuc58zWDyEqnQZ",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T08:30:00.000Z",
"end":"2015-12-08T09:30:00.000Z",
"teachers":[
],
"clients":[
],
"clientLimit":15
},
{
"_id":"EsqygwCCPucGhx9nP",
"title":"New event",
"type":"collectif",
"product":"passeport",
"date":"2015-12-08T00:00:00.000Z",
"start":"2015-12-08T09:30:00.000Z",
"end":"2015-12-08T10:30:00.000Z",
"teachers":[
"eLExMRh3TT5eYWpki",
"wxFjH39M9kuBTv4zN"
],
"clients":[
],
"clientLimit":10
}
]
}
});

Resources