How to find and update specific value in nested object array in typescript - reactjs

I have a nested object array with n level like this:
const data = {
"id": null,
"label": "Locations",
"value": "Locations",
"expanded": true,
"children": [
{
"id": "A978919C-E99C-EB11-8F2E-A01D48E35246",
"value": "Tokyo ",
"label": "Tokyo ",
"checked": true,
"children": [
{
"id": "88887069-179A-EB11-9C25-00163EDCFF95",
"isDefault": true,
"locationId": "A978919C-E99C-EB11-8F2E-A01D48E35246",
"parentsId": null,
"createDate": "2021-06-20T19:03:55.190Z",
"updateDate": "2021-10-16T13:36:41.353Z",
"label": "RAJ - Automotive Japan Fa Fusoh",
"checked": true,
"children": [],
"disabled": false
}
]
},
.
.
]
}
I have an object
{
"id": "A978919C-E99C-EB11-8F2E-A01D48E35246",
"value": "Tokyo ",
"label": "Tokyo ",
"checked": false,
"_depth": 1,
"_id": "A978919C-E99C-EB11-8F2E-A01D48E35246",
"_parent": "rdts1-0",
"_children": [
"88887069-179A-EB11-9C25-00163EDCFF95"
],
"_focused": true
}
and I want to edit checked in the object array by using the IDs in the last object and its children, change each checked in object in the object array to false
I used DFS for the children but I didn't get a good result any help please.

Seems like recursion would suffice:
const data = {
id: null,
label: 'Locations',
value: 'Locations',
expanded: true,
children: [
{
id: 'A978919C-E99C-EB11-8F2E-A01D48E35246',
value: 'Tokyo ',
label: 'Tokyo ',
checked: true,
children: [
{
id: '88887069-179A-EB11-9C25-00163EDCFF95',
isDefault: true,
locationId: 'A978919C-E99C-EB11-8F2E-A01D48E35246',
parentsId: null,
createDate: '2021-06-20T19:03:55.190Z',
updateDate: '2021-10-16T13:36:41.353Z',
label: 'RAJ - Automotive Japan Fa Fusoh',
checked: true,
children: [],
disabled: false,
},
],
},
],
}
function setCheckedToFalse(childrenArr) {
// error handling
if (!Array.isArray(childrenArr)) {
return;
}
childrenArr.forEach((child) => {
// set to false
child.checked = false
// recursion for other children
setCheckedToFalse(child.children)
})
}
setCheckedToFalse(data.children)
console.log(data);

Not sure if I correctly understood the question, but the code below the checked value in the data object is set to false in case it exists in object.
const data = {
id: null,
label: 'Locations',
value: 'Locations',
expanded: true,
children: [
{
id: 'A978919C-E99C-EB11-8F2E-A01D48E35246',
value: 'Tokyo ',
label: 'Tokyo ',
checked: true,
children: [
{
id: '88887069-179A-EB11-9C25-00163EDCFF95',
isDefault: true,
locationId: 'A978919C-E99C-EB11-8F2E-A01D48E35246',
parentsId: null,
createDate: '2021-06-20T19:03:55.190Z',
updateDate: '2021-10-16T13:36:41.353Z',
label: 'RAJ - Automotive Japan Fa Fusoh',
checked: true,
children: [],
disabled: false,
},
],
},
],
};
const object = {
id: 'A978919C-E99C-EB11-8F2E-A01D48E35246',
value: 'Tokyo ',
label: 'Tokyo ',
checked: false,
_depth: 1,
_id: 'A978919C-E99C-EB11-8F2E-A01D48E35246',
_parent: 'rdts1-0',
_children: ['88887069-179A-EB11-9C25-00163EDCFF95'],
_focused: true,
};
// Gets all ids (nested ones included) from object
function getIdsHashMap(obj) {
const idsHashMap = {};
const loopThroughChildren = (children = []) => {
children.forEach((el) => {
idsHashMap[el] = true;
if (el._children) {
loopThroughChildren(el._children);
}
});
};
if (obj.id) {
idsHashMap[obj.id] = true;
}
loopThroughChildren(obj._children);
return idsHashMap;
}
// Sets checked in data to false if an id exists in object
function setCheckedValue(obj) {
const idsHash = getIdsHashMap(object);
const loopThgroughChildren = (children) => {
if (!Array.isArray(children)) {
return;
}
children.forEach((child) => {
// Checks, if id exists in hashmap from object
if (idsHash[child.id]) {
child.checked = false;
}
if (child.children) {
loopThgroughChildren(child.children);
}
});
};
if (obj.children) {
loopThgroughChildren(obj.children);
}
return obj;
}
console.log(setCheckedValue(data));

Related

Subtract value in array based on other collection mongoose

I have the following collections
const TransactionSchema = mongoose.Schema({
schedule: {
type: mongoose.Schema.ObjectId,
required: true,
ref: "Schedule"
},
uniqueCode: {
type: String,
required: true
},
item: {
type: mongoose.Schema.ObjectId,
required: false,
ref: "Item"
},
created: {
type: Date,
default: Date.now
},
status: {
type: String,
required: false
},
})
schedule
const ScheduleSchema = mongoose.Schema({
start: {
type: Date,
required: true,
},
end: {
type: Date,
required: false,
},
questions: {
type: Array,
default: [],
},
items: [{
item: {
type: mongoose.Schema.ObjectId,
require: true,
ref: "Item"
},
stock: {
type: Number,
required: true
}
}],
status: {
type: String,
required: false
},
})
I want to return how many times the item appear in transaction and reduce it with the number of total item I have in array of objects items in schedule collection.
For example I have the following data:
transaction
[
{
"_id":ObjectId('626134d547c28b6ecc6d0c6c'),
"schedule":624edc44ac2edc1cf07821de,
"uniqueCode":"312312312312",
"created":2022-04-21T10:41:25.901+00:00,
"item": 61efd8a812432135c08a748d,
"status": "Active"
},
{
"_id":ObjectId('62615ea3db7d00061b7cc437'),
"schedule":624edc44ac2edc1cf07821de,
"uniqueCode":"1213123123",
"created":2022-04-21T13:39:47.351+00:00,
"item": 624c6b26a41c439987b1eb42,
"status": "Active"
}
]
schedule
[
{
"_id":ObjectId('624edc44ac2edc1cf07821de'),
"start":2000-01-01T00:00:00.000+00:00,
"end":2000-01-01T00:00:00.000+00:00,
"questions":[
12,
32,
122
],
"items":[
{
"item":61efd8a812432135c08a748d,
"stock":120
},
{
"item":624c6b26a41c439987b1eb42,
"stock":1000
}
],
"status":"Active"
},
]
Item
[
{
"_id": ObjectId('61efd8a812432135c08a748d'),
"name": "Samsung S21"
},
{
"_id": ObjectId('624c6b26a41c439987b1eb42'),
"name": "Iphone 10"
}
]
I want to get the following result:
[
{
"item":"Samsung S21",
"total":119
},
{
"item":"Iphone 10",
"total":999
}
]
Note: I want the query to query one schedule data only so the result only shows the items in that schedule. The first row shows 119 from total stock of item 120 - 1 which is how many times the item appeared in transaction (where the status is active). The second row shows 999 because the item has appeared in one transaction.
Thank you. Sorry for my bad English.

MongoDB - How to Update or Insert object in array

I have the following collection
{
"likes": [],
"_id": "6086f47a3e8c0411f0a66d22",
"creator": "dimer",
"picture": "",
"title": "",
"body": "hello world",
"comments": [
{
"isReady": true,
"likes": [],
"_id": "6086fcf33e8c0411f0a66d25",
"creatorId": "607e50a16e852544d41a1d9d",
"creator": "dimer",
"body": "hello world",
"replies": [],
"timestamp": 1619459315854
},
],
"createdAt": "2021-04-26T17:12:26.632Z",
"updatedAt": "2021-04-27T04:22:28.159Z",
"__v": 0
},
I want to push into comment.replies a new reply if the comment and the post exists.
How to Update or Insert object into a nested array with conditions?
I tried this:
module.exports.createReply = async (req, res) => {
const user_ID = req.body.creatorId;
const post_ID = req.params.id;
const comment_ID = req.body.commentId;
if (!ID.isValid(user_ID) && !ID.isValid(post_ID) && !ID.isValid(comment_ID)) {
return res.status(400).send("ID unknown");
}
try {
console.log("hello woorld");
const reply = {
creatorId: user_ID,
creator: req.body.creator,
body: req.body.body,
timestamp: new Date().getTime(),
};
console.log("reply", reply);
await PostModel.findById(post_ID, (err, docs) => {
console.log(comment_ID);
const comment = docs.comments.find((comment) =>
comment._id.equals(comment_ID)
);
console.log("comment", comment);
if (!comment) return res.status(404).send("comment not found" + err);
comment.replies = [...comment.replies, reply];
return docs.save((err, docs) => {
if (!err) return res.status(200).send(docs);
return res.status(400).send(err);
});
});
} catch (error) {
return res.status(400).send(err);
}
};
I think I'm not reaching the replies because I'm getting this error:
{
"errors": {
"comments.4.creator": {
"name": "ValidatorError",
"message": "Path `creator` is required.",
"properties": {
"message": "Path `creator` is required.",
"type": "required",
"path": "creator"
},
"kind": "required",
"path": "creator"
}
},
"_message": "post validation failed",
"name": "ValidationError",
"message": "post validation failed: comments.4.creator: Path `creator` is required."
}
This is my model:
const nongoose = require("mongoose");
const PostSchema = nongoose.Schema(
{
creatorId: {
type: String,
// trim: true,
// required: true,
},
creator: {
type: String,
trim: true,
required: true,
},
title: {
type: String,
maxlength: 80,
},
body: {
type: String,
trim: true,
maxlength: 250,
required: true,
},
picture: {
type: String,
},
video: {
type: String,
},
likes: {
type: [String],
require: true,
},
comments: {
required: true,
type: [
{
isReady: {
type: Boolean,
default: true,
},
creatorId: {
type: String,
required: true,
},
creator: {
type: String,
required: true,
},
timestamp: Number,
body: {
type: String,
required: true,
trim: true,
},
likes: {
type: [String],
required: true,
},
replies: {
require: true,
type: [
{
isReady: {
type: Boolean,
default: true,
},
creatorId: {
type: String,
required: true,
},
creator: {
type: String,
required: true,
},
body: {
type: String,
required: true,
trim: true,
},
timestamp: Number,
},
],
},
},
],
},
},
{
timestamps: true,
}
);
module.exports = nongoose.model("post", PostSchema);
Like the error says, Path creator is required.
Make sure the reply has the 'creator' field.
To get the updated document in the update’s return value, you need to use findOneAndUpdate 1 or findAndModify methods. Both the methods have a parameter where you can specify to return the updated document. Note that the Mongoose ODM has corresponding methods, but may have slightly different syntax.
My solution:
module.exports.createReply = async (req, res) => {
const user_ID = req.body.creatorId;
const post_ID = req.params.id;
const comment_ID = req.body.commentId;
if (!ID.isValid(user_ID) && !ID.isValid(post_ID) && !ID.isValid(comment_ID)) {
return res.status(400).send("ID unknown");
}
try {
const reply = {
creatorId: user_ID,
creator: req.body.creator,
body: req.body.body,
timestamp: new Date().getTime(),
};
const query = { _id: post_ID };
const update = { $push: { "comments.$[elem].replies": reply } };
const options = { new: true, arrayFilters: [{ "elem._id": comment_ID }] };
await PostModel.findOneAndUpdate(query, update, options);
let updated = await PostModel.findOne({ _id: post_ID });
return res.status(200).send({
data: updated.comments.find((comment) => comment._id.equals(comment_ID)),
});
} catch (err) {
return res.status(400).send({ err: err });
}
};

I want to create checkbox checked in nested data in react js

My data is in nested array objects. I want to make checked/unchecked the nodes like a tree view. ie. when any child node is selected then the parent node is checked itself.
This is my nested JSON. From this object, I create a tree view from this data:
const nodes = [
{
value: "/app",
label: "app",
children: [
{
value: "/app/Http",
label: "Http",
children: [
{
value: "/app/Http/Controllers",
label: "Controllers",
children: [
{
value: "/app/Http/Controllers/WelcomeController.js",
label: "WelcomeController.js",
},
],
},
{
value: "/app/Http/routes.js",
label: "routes.js",
},
],
},
{
value: "/app/Providers",
label: "Providers",
children: [
{
value: "/app/Http/Providers/EventServiceProvider.js",
label: "EventServiceProvider.js",
},
],
},
],
},
{
value: "/config",
label: "config",
children: [
{
value: "/config/app.js",
label: "app.js",
},
{
value: "/config/database.js",
label: "database.js",
},
],
},
{
value: "/public",
label: "public",
children: [
{
value: "/public/assets/",
label: "assets",
children: [
{
value: "/public/assets/style.css",
label: "style.css",
},
],
},
{
value: "/public/index.html",
label: "index.html",
},
],
},
{
value: "/.env",
label: ".env",
},
{
value: "/.gitignore",
label: ".gitignore",
},
{
value: "/README.md",
label: "README.md",
},
];
I am using this function to make parent checked when child is checked.
checkChange(targetNode: any, event) {
/// debugger;
const targetNodeId = targetNode.id;
this.findIndexNestedforCheckbox(targetNode, targetNodeId);
let newTableData = [...this.state.tableData];
this.setState({ tableData: newTableData, isActionFooter: true });
}
findIndexNestedforCheckbox(data, index) {
if (data.id === index) data.isChecked = "Yes";
let result;
const i = (data.children || []).findIndex((child) => {
child.isChecked = "Yes";
return (result = this.findIndexNestedforCheckbox(child, index));
});
if (result) return [i, ...result];
}
npm install react-checkbox-tree
import React from 'react';
import CheckboxTree from 'react-checkbox-tree';
const nodes = [{
value: 'mars',
label: 'Mars',
children: [
{ value: 'phobos', label: 'Phobos' },
{ value: 'deimos', label: 'Deimos' },
],
}];
class Widget extends React.Component {
state = {
checked: [],
expanded: [],
};
render() {
return (
<CheckboxTree
nodes={nodes}
checked={this.state.checked}
expanded={this.state.expanded}
onCheck={checked => this.setState({ checked })}
onExpand={expanded => this.setState({ expanded })}
/>
);
}
}

Difficulties to query nested arrays with multiple itens Mongoose

I`ve modeled a document to be:
let UserSchema = new Schema({
name: { type: String, required: true, max: 50, unique: true },
email: {type: String, required: true, max: 50, unique: true},
password: {type: String, required: true, max: 20},
monitoringProject: [
{
projectName: { type: String, required: true, max: 30},
token: { type: String, required: true},
dispositives: [
{
name: { type: String, required: true, max: 15},
value: { type: String, required: true},
token: { type: String}
}
]
}
],
controlProject: [
{
projectName: { type: String, required: true, max: 30},
token: { type: String, required: true},
dispositives: [
{
name: { type: String, required: true, max: 15},
value: { type: String, required: true},
token: { type: String}
}
]
}
]
});
In the monitoringProject, for example, I can log too many different projects, and, to each project, I can log too many dispositives. So, I have nested arrays. In other project, where I have just one project, and many dispositives, I can list them and search for just one dispositive. But in this case, like this:
[ { "_id": "5ee18ece1ea5af75bae55f91", "monitoringProject": [ { "dispositives": [ { "_id": "5ee18ef31ea5af75bae55f9c", "name": "Dispositivo 1", "token": "$2b$15$NntmY9ihNZ7R1Vg1WMtmzOSjlfCoKIuHLofF6g5tKXA57WLLc2At2" }, { "_id": "5ee18ef81ea5af75bae55f9e", "name": "Dispositivo 2", "token": "$2b$15$OZB7HbDLvonsv6A71ozW7.yVY2vJOipTCj0AH7XzoafQwwDho.jpm" }, { "_id": "5ee18efc1ea5af75bae55fa0", "name": "Dispositivo 3", "token": "$2b$15$0hpDzNeTO2qJzBVyAHc/UesrnIRi/YpeAlpCLewNhmfl6fe3SEN0i" }, { "_id": "5ee2278d0754817853134bf3", "name": "Dispositivo 4", "token": "$2b$15$ldC5/CyxITPJGUvtXJ.2S.D6a3FBftg6ctQeS4ne/9xpMP5PPiszK" }, { "_id": "5ee2288956fc4c7870044395", "name": "Dispositivo 6", "token": "$2b$15$3rJt.gXEi/gALvrwxVUsWuwF2RUcBmZcoFOQeXwF45ZuKQrB3AGHG" }, { "_id": "5ee6d23d1756b7a8384bcff0", "name": "Dispositivo 7", "token": "$2b$15$C3I9STKJpf9i/7hzhvHEs.IizXpOEmgRTD3hd7ZSdcvATb73Z0zNC" } ], "_id": "5ee18ede1ea5af75bae55f94", "projectName": "Projeto 2", "token": "$2b$15$xaytMbMnGd3BMAGapX8nn.imvkQKetqx0OIlUUyP3gCxlKz/G6DiG" } ] } ]
I can only list all the Dispositives. I want to return just, for example, "Dispositivo 2".
I used to querys:
await User.find({ email: req.body.email, monitoringProject: { $elemMatch: { token: req.body.projecttoken, dispositives: { $elemMatch: { token: req.body.dispositivetoken } } } } }, { "monitoringProject.$.dispositives": 1} )
or
await User.find({ email: req.body.email, 'monitoringProject.token': req.body.projecttoken, 'monitoringProject.dispositives.token': req.body.dispositivetoken}, { 'monitoringProject.dispositives.$': 1 })
Using find or findOne. How can I return just the document I want? I tried so many different ways, but with no lucky.

Update state using nested map es6

My state has an array of objects that also contains an array of objects.
var state = {
prop1: null,
categories: [
{
categoryId: 1,
tags: [
{
tagId: 1,
name: 'AA11',
status: true,
},
{
tagId: 2,
name: 'AA22',
status: false,
}
]
},
{
categoryId: 2,
tags: [
{
tagId: 1,
name: 'BB11',
status: true,
},
{
tagId: 2,
name: 'BB22',
status: false, // let's say i want to toggle this
}
]
},
]
};
I have an action that will toggle a status of a tag. This action will receive parameters categoryId and tagId.
So far I've come up with this but it doesn't work
return {
...state,
categories: state.categories.map((category) => {
category.tags.map(tag => (
(tag.tagId === action.tagId && category.categoryId === action.categoryId) ? {
...tag,
status: !tag.status,
} : tag));
return category;
}),
};
I finally fixed the map code.
return {
...state,
categories: state.categories.map(category => ((category.id === action.categoryId) ?
{
...category,
tags: category.tags.map(tag => (tag.id === action.tagId ? {
...tag, status: !tag.status,
} : tag)),
} : category)),
};

Resources