Comparing original form data to edited data - javascript

I have a form that is built in with React with react-hook-form that allows users to add dynamic steps using the useFieldArray method which comes with react-hook-form.
My problem is that how can I compare the original data that was passed into the form with the new edited data so I can make the corresponding changes to my backend? Here is an example of the original data:
{
"id": "1",
"name": "Recipe Name",
"method": [ {id:1, method: "method 1", recipesId: 1} , {id:2, method: "method 2", recipesId: 1}],
"ingredients": [{id:1, ingredient: "ingredient 1", recipesId: 1} , {id:2, ingredient: "ingredient 2", recipesId: 1}]
}
Then the user makes the following changes:
{
"id": "1",
"name": "Recipe Name Example",
"method": [ {id:1, method: "method 1 example", recipesId: 1} , {id:3, method: "method 3", recipesId: 1}],
"ingredients": [{id:2, ingredient: "ingredient 2 change", recipesId: 1}]
}
So the following has been done:
UPDATE - The name has been changed.
The method array:
UPDATE - The method of id 1 has been changed from "method 1" to "method 1 example"
DELETE - The method with id 2 has been deleted
INSERT - Method 3 has now been added.
The ingredients array:
DELETE - The first ingredient with id 1 has been deleted
UPDATE - The ingredient with id 2 has updated the ingredient from "ingredient 2" to "ingredient 2 change"
Should the changes be in a new object to show changes or individual Insert, Update and Delete arrays/objects?
Thankyou.

Related

How to add object in Array of Objects using Node js in Mongodb?

I want to update my courseModules inside MasterCourse. In below JSON I have two Objects in courseModules. I want if moduleId exist in courseModules then update it else create a new object and return the courseModules with updated value.
I am using Node js and mondodb, mongoose. Not able to find how can I achieve this functionality.
JSON OR MONGODB Data:
"MasterCourse": [
{
"_id": "6392f2611e7d670eca9712fa",
"courseTitle": "My Course Title",
"awardURL": "award.png",
"courseModules": [
{
"moduleId": 0,
"moduleTitle": "Module Title 1",
"moduleDescription": "Module 1 description",
"totalSessions": 3,
"_id": "6392f2611e7d670eca97e12d"
},
{
"moduleId": 1,
"moduleTitle": "ModuleTitle 2",
"moduleDescription": "Module 2 description",
"totalSessions": 4,
"_id": "6392f2611e7d670eca9711wd"
},
],
}
]
Query want to perform:
{
"moduleId": 2,
"moduleTitle": "Module Title 3",
"moduleDescription": "Module 3 description",
"totalSessions": 8,
}
To add if item not exist -
masterCourse.updateOne({ "_id": req.params.id }, { $addToSet: { "courseModules": req.body } })
To update the value if exist -
masterCourse.updateOne({ "_id": req.params.id, "courseModules._id": ModuleID }, { $set: { "courseModules": req.body } })
These queries works for me, you can change the variable's name according to your data or requirement.

React bootstrap table 2 programmatically select filter

I'm trying to follow this example. I've pretty much replicated it line for line, adding in 5 products as that data isn't given in the example. Everything displays correctly so in theory I've set it up correctly, however the filter doesn't seem to work like it does in the example.
Any ideas? This is what I have:
https://stackblitz.com/edit/react-mmvhyv?file=Table.js
Issue is with products data quality field and selectOption fields , they are is matched
It tries to compare the products data quality with selectOption's key
So either you change products
const products = [
{"id": "1", "name":"john", "quality":"unknown"},
{"id": "2", "name":"jane", "quality":"good"},
{"id": "3", "name":"bob", "quality":"Bad"},
{"id": "4", "name":"ralph", "quality":"Bad"},
]
To :
const products = [
{"id": "1", "name":"john", "quality":2},
{"id": "2", "name":"jane", "quality":0},
{"id": "3", "name":"bob", "quality":1},
{"id": "4", "name":"ralph", "quality":1},
]
WORKING DEMO
OR
change selectOptions to :
const selectOptions = {
'good' : 'good',
'Bad' : 'Bad',
'unknown' : 'unknown',
};
const handleClick = () => {
qualityFilter('good'); // <---- here to
};
WORKING DEMO
In case you are calling API and populating your table, you need to check the response data and map it with the text displayed on UI.
For eg:
{
"ID": 1,
"CreatedAt": "2021-09-02T04:30:45.37+05:30",
"UpdatedAt": "2021-09-02T04:30:45.37+05:30",
"DeletedAt": null,
"Gender":"male",
"roll_no": 1,
"first_name": "Ravi",
"use_transport": false
}
Suppose we want to add select filter on use_transport and Gender.
Observe that use_transport is boolean as false and Gender is string "male" not capitalized. On UI if you are representing this two field as
use_transport="false" and Gender="Male". Then you need to create options map as follows,
const genderSelectOptions = {
"male": "Male",
"female": "Female",
"other": "Other"
};
const booleanSelectOptions = {
true:"true",
false: "false"
}
The key will be the value coming in response and the value of the map will be the value you are representing on the UI.
NOTE: It is important to have one unique ID in your table, you can keep it hidden. Filter uses that ID internally to distinguish the unique record.
The unique key has to be then bind as keyField in Bootstrap table tag
<BootstrapTable
striped hover condensed pagination={true}
search
keyField='ID'
data={this.state.students}
columns={this.state.columns}
filter={filterFactory()}
pagination={paginationFactory()} />

Mongoose: Filter nested documents

I have a MongoDB collection with documents that follows this shape:
"peopleList": [
{
"_id": "List 1 id",
"name": "List 1",
"people": [
{
"_id": "A Person id",
"name": "A Person",
"email": "person#email.com"
},
{
"_id": "Another Person id",
"name": "Another Person",
"email": "another.person#email.com"
},
],
},
{
"_id": "List 2 id",
"name": "List 2",
"people": [
{
"_id": "A Person id",
"name": "A Person",
"email": "person#email.com"
},
],
}
]
As you can see, the same Person object can appear in multiple lists.
So what I want is to retrieve all lists that a given person is part.
For e.g:
Passing _id: "A Person id" -> the query should return List 1 and List 2,
Passing _id: "Another Person id:" -> the query should return only List 1.
I tried this query:
await PeopleList.find({ people: { _id: 'A person id' } });
But the query returned an empty array, even 'A person id' is a document present in many lists.
EDIT
Sharing the Fahad answer, the correct query is:
await PeopleList.find({
people: { $elemMatch: { _id: mongoose.Types.ObjectId('A person id') }
}});
Lets assume that your mongo schema name is PeopleList so your filter query will be like this
PeopleList.find({people : {$elemMatch:{_id: mongoose.Types.ObjectId('321321321321321')}});
For more info you can see documentation here
You have to use $elemMatch and $in to find in array. So try like this
"people": { $elemMatch: { "_id": { $in: [mongoose.Types.ObjectId(params.id) ] } } }

JSON data filtering using javaScript [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have assigned a task to group data in angular js using underscore js.
My JSON :
data = [
{
"Building*": "Building A",
"Wing*": "Wing C",
"Floor*": "Floor 3",
"Room Name*": "Room 3",
"Room Type*": "AC",
"Location*": "Location 1",
"Device ID*": 27,
"Category*": "Soap Hygene",
"Dispenser Name*": "Dispenser 34",
"Type*": "Manual",
"Cartridge Type*": "Type 1",
"Date of installation": "2016-04-11T06:06:22 -06:-30",
"Contact Last Name": "Maynard",
"Email Address": "thomas.boscher#gmail.com",
"Mobile Number with country code": "+1 (949) 590-3465",
"Description": "Description of device",
"Model": 37
},
{
"Building*": "Building B",
"Wing*": "Wing B",
"Floor*": "Floor 3",
"Room Name*": "Room 1",
"Room Type*": "AC",
"Location*": "Location 3",
"Device ID*": 26,
"Category*": "Soap Hygene",
"Dispenser Name*": "Dispenser 33",
"Type*": "Manual",
"Cartridge Type*": "Type 2",
"Date of installation": "2015-07-24T12:42:24 -06:-30",
"Contact Last Name": "Holland",
"Email Address": "thomas.boscher#gmail.com",
"Mobile Number with country code": "+1 (947) 491-2353",
"Description": "Description of device",
"Model": 32
}
]
I need data in below format, where it has each building details containing the wing and floor data
updateData = [{
building: 'Building A' ,
buildingData:[ {
wing: "Wing A",
wingData: [{
floor:'Floor 2',
floorData:[{
room:'Room 3',
roomData:[]
}]
}]
}]
}];
I tried :
js fiddle
But it fails. Need help. Thanks in advance.
From my understanding you want to groupBy in the following nested order:
Building ->> Wing ->> Floor ->> Room
You can try calling groupBy recursively (or looping through, up to you) by passing an array of the order of nested attribute you want to groupBy. Try this snippet below:
const nestedOrder = ['Building*', 'Wing*', 'Floor*', 'Room Name*']
function groupFilter (rawData, attrList) {
if (attrList.length == 0) return rawData
var currentAttr = _(attrList).first()
return _(rawData)
.chain()
.groupBy(currentAttr)
.map((list, attrName) => Object({
[currentAttr]: attrName,
[`${currentAttr}Data`]: groupFilter(list, _(attrList).rest())
}))
.value()
}
console.log(groupFilter(data, nestedOrder))
The raw data will then be compacted to the deepest nested attribute, in this case 'Room Name*', you can then write your custom filter to output what you want RoomData to hold.
Not sure if its the right way to do it, but if runtime isnt a big issue for you then I think you can make it work fine.
Hopefully this helps/works out for you.

Lodash: filter a nested object by multiple properties

Consider the following example:
var products = {
"Products": [{
"Title": "A",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 2", "Type 3"]
}, {
"Name": "Market",
"Properties": ["Market 1", "Market 2", "Market 3", "Market 4"]
}, {
"Name": "Technology",
"Properties": ["Tech 1", "Tech 2"]
}]
}, {
"Title": "B",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 3"]
}, {
"Name": "Market",
"Properties": "Market 1"
}, {
"Name": "Technology",
"Properties": ["Tech 1", "Tech 3"]
}]
}, {
"Title": "C",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 2", "Type 3"]
}, {
"Name": "Market",
"Properties": ["Market 2", "Market 3"]
}, {
"Name": "Technology",
"Properties": ["Tech 2", "Tech 3"]
}]
}]
}
I'm trying to filter products by their properties so consider I'm using an array to keep track of my selected filters:
var filters = ['Type 3', 'Tech 1'];
With these filters I would like to return product A and product B.
I currently have this:
var flattenedArray = _.chain(products).map('Categories').flatten().value();
var result= _.some(flattenedArray , ['Properties', 'Tech 1']);
But I'm stuck on how to combine the properties for a combined search.
Use _.filter() to iterate the products. For each product combine the list of properties using _.flatMap(), and use _.intersection() and _.size() to find the amount of filters that exist in the categories. Compare that to the original number of filters, and return comparison's response.
var products = {"Products":[{"Title":"A","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 1","Market 2","Market 3","Market 4"]},{"Name":"Technology","Properties":["Tech 1","Tech 2"]}]},{"Title":"B","Categories":[{"Name":"Type","Properties":["Type 1","Type 3"]},{"Name":"Market","Properties":"Market 1"},{"Name":"Technology","Properties":["Tech 1","Tech 3"]}]},{"Title":"C","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 2","Market 3"]},{"Name":"Technology","Properties":["Tech 2","Tech 3"]}]}]};
var filters = ['Type 3', 'Tech 1'];
var result = _.filter(products.Products, function(product) {
return filters.length === _(product.Categories)
.flatMap('Properties')
.intersection(filters)
.size();
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
If I understand you question correctly, this code may help:
_.filter(
products.Products,
product => _.difference(
filters,
_.chain(product.Categories).map(category => category.Properties).flatten().value()
).length === 0
);
It calculates a union of all properties for each product:
_.chain(product.Categories).map(category => category.Properties).flatten().value()
And then checks that it contains all filters array elements, using _.difference method.
Hope it helps.
another fancy way through _.conforms
var res = _.filter(
products.Products,
_.conforms({'Categories': function(categories) {
return _.chain(categories)
.flatMap('Properties') // flat arrays
.uniq() // remove dublicates
.keyBy() // transform to objects with Properties keys
.at(filters) // get objects values by filters
.compact() // remove undefineds
.size() // get size
.eq(filters.length) // compare to filters size
.value();
}
}))
This will work for a list of items where the givenProperty you want to filter on is either a string like 'doorColour' or an array of strings representing the path to the givenProperty like ['town', 'street', 'doorColour'] for a value nested on an item as town.street.doorColour.
It also can filter on more than one value so you could you just need pass in an array of substrings representing the string values you want to keep and it will retain items that have a string value which contains any substring in the substrings array.
The final parameter 'includes' ensures you retain these values if you set it to false it will exclude these values and retain the ones that do not have any of the values you specified in the substrings array
import { flatMap, path } from 'lodash/fp';
const filteredListForItemsIncludingSubstringsOnAGivenProperty = (items, givenProperty, substrings, including=true) => flatMap((item) =>
substrings.find((substring) => path(givenProperty)(item) && path(givenProperty)(item).includes(substring))
? including
? [item]
: []
: including
? []
: [item])(items);
E.g. fLFIISOAGP(contacts, ['person','name'], ['Joh','Pau',Pet']);
with items of structure {contact, business:null, personal:{name:'John'}}.
For the original question - this will also work - I would use this repeatedly on a list of items to filter with different keys to filter on more than one property.
const firstFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty(
products.Products,
["Categories", "0", "Properties"],
["Type 3"]);
const secondFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty(
firstFilteredResult,
["Categories", "2", "Properties"],
["Tech 1"]);
expect(secondFilteredResult[0]['Title']).to.equal( "A");
expect(secondFilteredResult[1]['Title']).to.equal( "B");
expect(secondFilteredResult.length).to.equal(2);

Categories

Resources