Upsert array value in NodeJS - javascript

I have a simple scenario where I am trying to update an array value that is part of an object, but the object does not seem to reflect the update.
Code:
var request =
{
description: 'my-desc',
details: []
};
request.details['shelf-info'] =
[
{
key: 'ShelfNumber',
value: '100'
}
];
console.log(JSON.stringify(request))
With the assignment of shelf-info, I would have expected the resulting output to be similar to:
Desired Output:
{ "description": "my-desc", "details": { "shelf-info": [ "key": "ShelfNumber", "value": "100" ] } }
but the update doesn't seem to have taken effect:
Actual Output:
{"description":"my-desc","details":[]}
I have found that I can add simple objects (strings) to an array using append, but shelf-info may or may not already be in the request.details section by the time this code gets executed...how would I handle both cases?

You want a plain object ({}) for details, not an array ([]).
When arrays are serialized to JSON, the JSON output only includes values that are stored in whole-number indices. Arrays may validly have other properties whose key names are not non-negative integers (such as the string shelf-info) but those properties are not included the JSON serialization of the array.

You're using an array as if it's an object, which it technically is, but that won't add anything to the array, and it won't convert the array to a regular object with key/value pairs.
Easy fix:
var request = {
description: 'my-desc',
details: { }
};
Also since it's 2020 you should be using let instead of var in most cases.

Try Below. Detail property should be an object.
var request =
{
description: 'my-desc',
details: {}
};
request.details['shelf-info'] =
[
{
key: 'ShelfNumber',
value: '100'
}
];
console.log(JSON.stringify(request))

Related

Map object into array of objects

I am having an object which consists of different key value pairs as below:
{1: '20', 2: '2340', 3: '1420', ...., so on} (Not related to any math equation)
I want to convert the object keys which are dynamic and have the output something like below:
[{"rate_id": '20'}, {"rate_id": '2340'}, {"rate_id": '1420'}, ...., so on}]
Any answers or suggestions are appreciated!
You should really look at how you make the first object. Looks like it is a array converted to an object. Would be easier to stat with a normal array.
If you can't do anything to change the initial value you can get the values from the object, which will return an array of the values. Then map it to the type you want.
const currentObject = { 1: "20", 2: "2340", 3: "1420" };
// Get values to a array and map them to {rate_id: value}
const rates = Object.values(currentObject).map((value) => ({
rate_id: value,
}));
// rates will look like this [{ rate_id: "20" }, { rate_id: "2340" }, { rate_id: "1420" }];

Finding value in json array and replacing it using Typscript [duplicate]

This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 2 years ago.
I have a file with 1000s of json rows like below. Im having difficulties locating a specific key in the array.
example json:
{"connection":"98374"
,"db":"8",
,"timestamp":"159905411631"
,"event":"DataCatch"
,"data":[{"key":"ruleid","value":"111"}
,{"key":"responseid","value":"155-response-4"}
,{"key":"responsetype","value":"Capture"}
,{"key":"reason","value":"ClientVisit"}
,{"key":"subreason","value":""}
,{"key":"score","value":"0.00"}
,{"key":"comment","value":""}]
}
I need to be able to find the "reason" key in the "data" array and replace the "value" with "test". The "data" array doesn't always appear on every json row, only when the "event" "dataCatch" is present.
I can parse it into a variable but I can only call the "data" array as a whole. Any ideas how to target specific values in an array?
Having a little trouble with this in Typescript.
There are any number of ways to go about this, but here's one.
First, parse your JSON into an array of objects.
Each element of the array will then look something like this:
{
connection: '98374',
db: '8',
timestamp: '159905411631'
event: 'DataCatch',
data: [
{ key: 'ruleid', value: '111' },
{ key: 'responseid', value: '155-response-4' },
{ key: 'responsetype', value: 'Capture' },
{ key: 'reason', value: 'ClientVisit' },
{ key: 'subreason', value: '' },
{ key: 'score', value: '0.00' },
{ key: 'comment', value: '' },
],
}
Let's call our array of objects allData, so we can refer to it later.
Now we can begin our "surgery".
We'll work from the inside-out, first looking at what needs to be done to a specific entry in an element's data array.
Here's a function that will do just what we need:
function updateReason(entry) {
if (entry.key === 'reason') {
return { ...entry, value: 'test' };
} else {
return entry;
}
}
This function checks if the provided entry has a key with a value of 'reason', and -- if so -- returns a new entry that is identical to the provided one except its value is 'test'.
How can we use this to update an entire data array (in an entry that has data, that is)?
We simply delegate the work to our dear friend map:
function updateData(data) {
// or simply `data.map(updateEntry);`
return data.map(entry => updateEntry(entry));
}
We're slowly working our way "outwards".
What about updating an entire entry in our big allData array (which may or may not contain data)?
// I've called such an entry a "collection", because I already used the name
// "entry" above :(
// A "collection" is just an entry in the big `allData` array.
function updateCollection(collection) {
if (collection.event === 'DataCatch') {
return {
...collection, // Leave everything else the way it is
data: updateData(collection.data), // But update the `data` array
};
} else {
return collection;
}
}
So close.
The last thing we need to do is apply this transformation to every element of our parsed allData array:
// or `allData.map(updateCollection);`
const updatedData = allData.map(collection => updateCollection(collection));
Also:
Q: Wouldn't it be cheaper to mutate the entry?
A: It would be cheaper, but not that much cheaper, due to a large amount of "structural sharing" that occurs here. I would recommend this approach unless you either need to mutate your input for some reason, or performance requirements demand it.
You need to map over the data key in your data variable like this.
data.data = data.data.map((item) => {
if (item.key === "reason") {
item.value = "test";
}
return item;
});
the data key is an array of values, so you need to loop through it and compare the value of the key property to the value you are looking for, if it matches then you can update the value property
https://codesandbox.io/s/angry-shirley-1gh83?file=/src/index.ts:666-782

Creating an array within an object within an object

Using Javascript, how do I create an array within an object that's within an object, so that my value is stored at: main[1].type[1][0]
I have tried and my code which does not work is as follows:
let main = []
main[1] = {type: {1:['Value1', 'Value2']}, {2:['Value3', 'Value4']}};
console.log(main[1].type[0][1]);
I expect main[1].type[1][0] to be 'Value1' but it is undefined
You're not getting undefined. You have a syntax error. A comma should either be separating array values, or separating object entries. You have a comma here, in an object, so it is expected to have a key after it, not a {
main[1] = {type: {1:['Value1', 'Value2']}, {2:['Value3', 'Value4']}};
|
|
Remove the } and { around this comma
Remove the } and { around the comma so that {1:['Value1', 'Value2'], 2:['Value3', 'Value4']} becomes a single object with two keys:
const main = [];
main[1] = {type: {1:['Value1', 'Value2'], 2:['Value3', 'Value4']}};
console.log( main[1].type[1][0] );
First your declaration is wrong and will not works.
{type: {}, {}} isn't a valid JSON and you must wrap it into [] to create array of object {type: [{}, {}]}.
Also by adding a level you will have to ask for: main[1].type[0][1][0] to get the complet path to Value1
let main = []
main[1] = {type: [{1:['Value1', 'Value2']}, {2:['Value3', 'Value4']}]};
console.log(main[1].type[0][1][0])
Your problem is you can not create an object with a numbered object inside it you have to use the array notation var variableName = [/*variable values here separated by commas*/]
This will fix your problem:
let main = []
main[1] = {
type: [
['Value1', 'Value2'],
['Value3', 'Value4']
]
};
console.log(main[1].type[0][1]);
Breaking down your issue, an object must be "zero or more pairs of property names and associated values of an object." The second value in the question's code does not have a key, causing an uncaught SyntaxError.
Here's an object literal that returns your desired result:
const main = {
1: {
type: { 1: ['Value1', 'Value2'] },
otherType: { 2: ['Value3', 'Value4'] },
},
};
main[1].type[1][0]
=> "Value1"
Object initializer docs
Another option could be to use sparse arrays :
let main = [, { type: [, ['Value1', 'Value2'], ['Value3', 'Value4'] ] } ];
console.log(main[1].type[1][0]);

Excluding missing keys from JSON comparison

I have two JSON documents that I want to assert equal for Jest unit testing. They should be equal, except the second one has one more key: _id.
Example:
doc1.json
{
username: 'someone',
firstName: 'some',
lastName: 'one',
}
doc2.json
{
_id: '901735013857',
username: 'someone',
firstName: 'some',
lastName: 'one',
}
My code currently looks like this:
const result = await activeDirectoryUserCollection
.findOne({username: testUser1.username});
expect(result).toBe(testUser1);
Obviously this gives the error that they are not equal, just because of that one value.
I'm looking for an alternative to .toBe() that doesn't completely compare the docs, but checks if one is a subset of another. (or something like that).
Alternatively I would appreciate someone to point me to a module that could help me out.
I would checkout Lodash module's .isMatch function.
It performs a partial deep comparison between object and source to determine if object contains equivalent property values.
https://lodash.com/docs/4.17.11#isMatch
Example:
var object = { 'a': 1, 'b': 2 };
_.isMatch(object, { 'b': 2 });
// => true
_.isMatch(object, { 'b': 1 });
// => false
You can iterate through one Object and use the key to assert value in both Objects. Read More for...in
const result = await activeDirectoryUserCollection
.findOne({username: testUser1.username});
for (const prop in testUser1) {
if (testUser1[prop]) {
expect(result[prop]).toBe(testUser1[prop]); // or use .toEqual
}
}
I don't think you need to look outside jest for this. You can use expect.objectContaining(), which is described in the docs as:
expect.objectContaining(object) matches any received object that recursively matches the expected properties. That is, the expected object is a subset of the received object. Therefore, it matches a received object which contains properties that are present in the expected object.
You could use it like:
test('objects', () => {
expect(doc2).toEqual(
expect.objectContaining(doc1)
);
});

JS Remove multi-dimensional data property using array of properties

Basically I have got an object, which will be multi-dimensional and the properties could be named anything and it could have many dimensions.
At some point I will need to append/splice a property within this object, from code which won't know it's position.
So, an example object:
let obj = {
response: {
locations: {
data: [
0: Object,
1: Object,
2: Object,
]
}
},
endpoint: null
}
I need to splice out data.locations.data[1], the only information I have is the below array and the index. Obviously I will know the first property will be response.
['locations','data']
index: 1
Edit:
My mistake, the data property has an array value not an object!
You can use Array#reduce() and pass in obj.response as the start value to get at the nested parent which based on the array shown would be obj.response.locations.data.
Then splice() the indexed item in that parent or do whatever other modifications are needed
const arr = ['locations','data'],
index= 1,
obj = {
response: {
locations: {
data: [{id:1},{id:2}, {id:3}]
}
},
endpoint: null
}
const targetArr = arr.reduce((a,c)=> (a[c]), obj.response);
targetArr.splice(index,1);
console.log(obj)

Categories