How to filter deeply stacked data inside an object(and edit\delete it afterwards)? - javascript

I have a problem here, and I can't find out how to solve it. I have an object with many levels. There is arrays with objects inside my object, and they have their arrays with objects too. Let me show you somekind of example here:
{
sections: [
{
currency_sections: [
{
positions: [
{
id: 131,
quantity: 24
},
{
id: 133,
quantity: 1
}
],
key: value,
key: value
},
{
positions: [
{
id: 136,
quantity: 2
},
{
id: 137,
quantity: 3
}
],
key: value,
key: value
}
],
key: value,
key: value
}
],
key: value,
key: value
}
I build my data via handlebars template. Which is not really important. But on my page I can change, let's say, quantity of the position. When I do that I have only id of the position I changed and new quantity.
So basically I need to filter my object to find one object in positions arrays that matches via id key and change quantity there.
Also I can delete whole position, and in that case I need to find position object with id needed and delete whole object.
The thing I can't understand is how I can filter all my data at once. And how can I manipulate unnamed object if I will find it.
And let's say I filtered it somehow. Can I return full path to that object for later use? In example - sections[0].currency_sections[1].positions[0] ? Because if I can do that than deleting and editing should be simple enough.
At this point I don't really have the time to redo everything on something more suitable like angular or ember. Although I have underscore and jquery.

Just wanted to update my question. At the end I just created a method that builds index of my elements.
function _createItemsIndex(data) {
if (!$.isEmptyObject(data)) {
$.each(data.sections, function (sectionIndex, section) {
$.each(section.currency_sections, function (curSecIndex, curSec) {
$.each(curSec.positions, function (positionIndex, position) {
_items.push({
id: position.id,
quantity: position.quantity,
price: parseFloat(position.price) || 0,
index: [sectionIndex, curSecIndex, positionIndex]
});
});
});
});
}
}
Thank you levi for your comments

Related

(closed) How to increment a value which is in an object which is in an array which is in another object

So I'm trying to code a bot in discord.js where you basically have items in an inventory and when I use an item, its durability goes down. I am using MongoDB Atlas to store all the data. The structure of the inventory is:
user: {
id: 'user-id',
name: 'user-name',
inventory: [
{
name: 'item',
durability: 5
,
{
name: 'another-item',
durability: 20
}
]
}
So I just wanted to find a way to basically just decrement the durability in the item without updating any other item in the inventory array but I wasn't able to get a way to do it.
You can use arrayFilters to update only the value you want.
Also you can use $inc to increment the value (in this case increment by -1, i.e, decrement)
db.collection.update({
"id": "user-id"
},
{
"$inc": {
"inventory.$[element].durability": -1
}
},
{
"arrayFilters": [
{
"element.name": "item" //here use the name of the object you want to update
}
]
})
Example here

JavaScript: Take an index of an item in an array, and figure out what the index of the same item would be if the array were reversed?

The Setup
I have an array of objects called Elements. They are visually laid out like layers in a photoshop document. I have stripped out most of the data from each element for brevity. But the data changes for each element, because they are all different.
elements = [
{
name: 'First Piece',
},
{
name: 'Second',
},
{
name: 'Third',
},
{
name: 'Fourth', // is selected
},
{
name: 'Fifth',
},
]
I keep track of which element is selected in an object using the index of the selected item. I use the index because it is always available to me at any given time or place the elements are represented. The object looks like this, sans the non relevant data:
selected = {
element: 3,
}
This all works great.
The Problem
The problem lies in what could be considered my Layers panel. When the elements are on the 'canvas', they are in the correct order with each element having a higher z-index. But in the layers panel, I have to reverse the array so that it visually makes sense. So the 'Fifth' element is on top.
The problem is when I need to take the value of selected, and apply it to the reversed elements array.
elementsReversed = [
{
name: 'Fifth',
},
{
name: 'Fourth', // this should be selected
},
{
name: 'Third',
},
{
name: 'Second', // would be selected
},
{
name: 'First Piece',
},
]
I can't use .findIndex() because the names could be set to the same value (for a reason) and there aren't really other attributes I could use to search through a reversed array and find the index that way. I am trying to avoid adding another key/value pair to my objects like an ID.
Is there a way to do this? Am I just being a dum dum?
Thank you.

Return true if an array within an array contains specific key

I have the following the object:
items: [
{
object_a {
id: "1",
value: "somevalue1"
}
},
{
object_b {
id: "2"
value: "somevalue2"
items:[
{
nested_object_a {
id: "3"
value: "somevalue3"
},
nested_object_b {
id: "4"
value: "somevalue4"
},
}
]
}
},
]
I can check if the value key exists in the initial items array:
items.some(item => item.hasOwnProperty("value"));
To see if the value key exists in the nested object_b item array I can do the following:
items[1].object_b.items.some(item => item.hasOwnProperty("value"));
Instead of specifying which number in the array to look in I need to make the final expression dynamic. I'm certain I need to do a find or a filter on the top level items, but I've had no luck with it so far.
I found that using an every function on the items allowed me to return the boolean value I required form the array. The problem this created is any array item that didn't have the object_b key on was returning null and breaking my app. It turns out I needed to use an optional chaining operator to get around this (.?).
Thanks to #ikhvjs for linking that stackedoverflow article.
Working code:
items.every(item => {
item.object_b?.items.some(item => item.hasOwnProperty("value"));
});

How to change the location of an object key value pair in JavaScript

I've seen similar questions to this one but in different languages and I am struggling to create a JavaScript equivalent.
I am receiving an object and through a function I want to change the location of one (or more) of the properties. For example,
With the original object of
{
individual: [
{
dob: '2017-01-01',
isAuthorized: true,
},
],
business: [
{
taxId: '123',
},
],
product: {
code: '123',
},
}
I would like to change the location of isAuthorized to be in the first object inside of the business array instead of individual.
Like so
{
individual: [
{
dob: '2017-01-01',
},
],
business: [
{
taxId: '123',
isAuthorized: true,
},
],
product: {
code: '123',
},
}
So far I was trying to create an object that would contain the key name and location to change it to, e.g.
{
isAuthorized: obj.business[0]
}
And then loop over the original object as well as the object with the location values and then set the location of that key value pair.
Basically, in this function I want to see that if the original object contains a certain value (in this case isAuthorized) that it will take that key value pair and move it to the desired location.
What you want can easily be achieved by using loadsh, here's a working snippet of how to restructure based on defined structure map. Extended this example to match what you want.
The example is doing a deep clone, if you are fine modifying the original object then skip that step to avoid the overhead.
// input data
const data = {
individual: [
{
dob: '2017-01-01',
isAuthorized: true,
},
],
business: [
{
taxId: '123',
},
],
product: {
code: '123',
},
};
// the structure change map
const keyMap = {
'individual[0].isAuthorized': 'business[0].isAuthorized'
};
function parseData(data,keyMap) {
const newData = _.cloneDeep(data);
for( let [source,dest] of Object.entries(keyMap) ) {
_.set(newData,dest,_.get(newData,source));
_.unset(newData,source);
}
return newData;
}
console.log(parseData(data, keyMap));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Note: loadsh's set consider any numeric value as an array index so if you are using a numeric object key then use loadash.setWith. I recommend reading examples in doc for a better understanding.
https://lodash.com/docs/4.17.15#set

Deep Object Comparison and Property Targeting in JavaScript

I am trying to find out if there any any es6 (or external library) ways to handle deep object comparison and parsing in JavaScript.
Take the following example, where I have a property history, which is an array, embedded within a property services, which is also an array:
{
_id: 4d39fe8b23dac43194a7f571,
name: {
first: "Jane",
last: "Smith"
}
services: [
{
service: "typeOne",
history: [
{ _id: 121,
completed: true,
title: "rookie"
},
{ _id: 122,
completed: false,
title: "novice"
}
]
},
{
service: "typeTwo",
history: [
{ _id: 135,
completed: true,
title: "rookie"
},
{ _id: 136,
completed: false,
title: "novice"
}
]
}
]
}
Now, say a new element is pushed onto the "history" array within the second "services" element, where (service : "typeTwo") -- on the "services" array. I need to identify that's happened, and pull out the entire parent element, because I also need to know what "service" within the "services" array had a new "history" element added.
Is there a way I can scan this entire object and not only determine when something's changed, but actually be able to pull out the section I need reference to? I'm open to either a native JS or JS library option here.
You can check for duplicates like this:
function isEqual(firstObject, secondObject) {
function _equals(firstObject, secondObject) {
let clone = {...{}, ...firstObject}, cloneStr = JSON.stringify(clone);
return cloneStr === JSON.stringify({...clone, ...secondObject});
}
return _equals(firstObject, secondObject) && _equals(secondObject, firstObject);
}
https://jsfiddle.net/b1puL04w/
If you considering libraries has stated, then lodash has _.isEqual which does perform a deep comparison between two values to determine if they are equal.
I have used it extensively for deep comparison in the past.

Categories

Resources