Add Extra Key value on existing object under loop - javascript

I have a data set like this:
[
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
},
]
Now For getting the value one by one I have created a loop. Under loop I am getting the value.
Now if I want to add extra key value on that object then how it will be done.?
I tried data[i].extrakey = "value";
console.log(data);
but it will not set.
Any help is really appreciated

Use map
array = array.map( s => Object.assign( s, {extrakey : "value" } ) );

You can use spread along with array.prototype.map to add the extra key:
var arr = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
},
];
var result = arr.map(e => ({...e, extraKey: 'value'}));
console.log(result);

You can see it in the example below. Just iterating over the array and adding a new key will alter the objects inside the array, because object is a reference type and you are just working with a reference which changes the original object.
const array = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
}
];
array.forEach(item => item.extraKey = 'value');
console.log(array);
Also if you want to change the array items, it will be better to not change the original objects, but create their copies and provide a new array.
const array = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
}
];
const newArray = array.map(item => Object.assign({}, item, { extraKey: 'value' }));
console.log(newArray);

var array = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
}
];
array = array.map( s => Object.assign( s, {extrakey : "value" } ) );

Related

How to get actual keys from MongoDB result array?

INPUT:
let array =[
{name:"xyz", email:"xyz#gmail.com", date:"22/10/2020" },
{name:"abc", email:"abc#gmail.com", date:"29/12/2020" },
{name:"efg", email:"efg#gmail.com", date:"20/01/2021" },
{name:"pqr", email:"pqr#gmail.com", date:"12/08/2020", age:"20" },
{name:"stu", email:"stu#gmail.com", date:"19/09/2020", age:"21" },
]
After performing certain operations I got the above array of objects as output from mongodb collection. From that array I want to get all keys and compare each and every object in an array and if any property present in any object not there in another object then I want to assign the property with empty string value.
To perform that operation I have written the code as shown below-
const keys = array.reduce(
(acc, curr) => (Object.keys(curr).forEach((key) => acc.add(key)), acc),
new Set()
);
const output = array.map((item) =>
[...keys].reduce((acc, key) => ((acc[key] = item[key] ?? ""), acc), {})
);
By performing above operations along with my original keys I am getting unnecessary keys like "$__", "$isNew", "_doc"
MY OUTPUT:
[
{
"$__": {
"activePaths": {
"paths": {
"_id": "init"
},
"states": {
"ignore": {},
"default": {},
"init": {
"_id": true
},
"modify": {},
"require": {}
},
"stateNames": [
"require",
"modify",
"init",
"default",
"ignore"
]
},
"strictMode": false,
"skipId": true,
"selected": {},
"fields": {},
"exclude": null
},
"$isNew": false,
"_doc": {
"_id": "62e6791b049e103f612f0882",
"name": "pqr",
"email": "pqr#gmail.com",
"date": "12/8/2020",
"age": "20",
},
"name": "pqr",
"email": "pqr#gmail.com",
"date": "12/8/2020",
"age": "20",
},
.
.
.
.
EXPECTED OUTPUT:
[
{
"name": "xyz",
"email": "xyz#gmail.com",
"date": "22/10/2020",
"age": ""
},
{
"name": "abc",
"email": "abc#gmail.com",
"date": "29/12/2020",
"age": ""
},
{
"name": "efg",
"email": "efg#gmail.com",
"date": "20/01/2021",
"age": ""
},
{
"name": "pqr",
"email": "pqr#gmail.com",
"date": "12/08/2020",
"age": "20"
},
{
"name": "stu",
"email": "stu#gmail.com",
"date": "19/09/2020",
"age": "21"
}
]
If I am using same code for normal array instead of resultant array from mongoodb I am getting correct output.
Please help me in resolving the above issue.
Query
if you have few fields and you know their names you can do it on server like bellow, in simple way
check if field (if missing it will be false) if its there keep old value, else add it with ""
the bellow doesn't work with boolean fields, if you have those you should check if type="missing" but in your case you dont have boolean fields so it will be ok
Playmongo
aggregate(
[{"$set":
{"name": {"$cond": ["$name", "$name", ""]},
"email": {"$cond": ["$email", "$email", ""]},
"date": {"$cond": ["$date", "$date", ""]},
"age": {"$cond": ["$age", "$age", ""]}}}])

Transform complex object into key value

I have an array
const arr = [
{
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"rank": 1,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:21.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
},
{
"id": 2,
"name": "Litecoin",
"symbol": "LTC",
"slug": "litecoin",
"rank": 20,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:22.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
}
]
And I want to transform the array to this
{
"BTC": "Bitcoin",
"LTC": "Litecoin",
}
Is there a better way than this?
const result = {}
arr.reduce((accum, val) => {
Object.assign(result, { [val.symbol]: val.name });
}, {})
console.log(result)
Use Object.entries() an each object which will return them as an array of arrays -- each sub-array will be a key/value pair ([key, value]) then use Object.assign() to create a new object ({[key]: value}) to return. Then flatten it so they are all in one array.
const arr=[{id:1,name:"Bitcoin",symbol:"BTC",slug:"bitcoin",rank:1,is_active:1,first_historical_data:"2013-04-28T18:47:21.000Z",last_historical_data:"2022-02-18T11:39:00.000Z",platform:null},{id:2,name:"Litecoin",symbol:"LTC",slug:"litecoin",rank:20,is_active:1,first_historical_data:"2013-04-28T18:47:22.000Z",last_historical_data:"2022-02-18T11:39:00.000Z",platform:null}];
const conv = array => {
let objects = array.map(obj => Object.entries(obj).map(([key, val]) => Object.assign({}, {[key]: val})));
return objects.flat();
};
console.log(conv(arr));
let arr = [
{
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"rank": 1,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:21.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
},
{
"id": 2,
"name": "Litecoin",
"symbol": "LTC",
"slug": "litecoin",
"rank": 20,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:22.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
}
]
// As suggested, here it is without having to create an initial array
let alternativeArray = arr.map((val) => {
return {[val.symbol]: val.slug}
})
console.log(alternativeArray)
Here is the answer to why the object key is being set in that format:
Javascript set object key by variable
The answer is
Object.fromEntries(arr.map(({symbol, name}) => [symbol, name]))

Sorting a nest object by datetime not working as expected

I am having some trouble sorting a nested object by its timestamp. I was hoping for some help...
This is what the object looks like and what I have so far...
useEffect(() => {
if (realtime.length) {
let unorderedmessage = realtime.concat(messages);
const orderedMessages = unorderedmessage
.slice()
.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
setMessages(orderedMessages);
}
}, [realtime]);
[
Object {
"_id": "a16edcb7-17e1-46ea-b8ce-5ec312d5eb6c",
"createdAt": 2020-04-23T01:51:48.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
],
"text": "2–> Olivia to Mike",
"user": Object {
"_id": "lTONqS9O00PhkxwHD2EYs05EMwu2",
"avatar": "123",
},
},
Object {
"_id": "5ef28d42-6f7c-45eb-a5e1-59ca700f56b7",
"createdAt": 2020-04-23T02:01:52.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
],
"text": "4–> Olivia to mike",
"user": Object {
"_id": "lTONqS9O00PhkxwHD2EYs05EMwu2",
"avatar": "123",
},
},
Object {
"_id": "1e07873f-f010-4e9d-be17-9bcb7793695b",
"createdAt": 2020-04-23T02:02:06.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"lTONqS9O00PhkxwHD2EYs05EMwu2",
],
"text": "5–> mike to Olivia",
"user": Object {
"_id": "OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
"avatar": "123",
},
},
Object {
"_id": "5fecafc3-c608-4156-b88c-f6c57e8e9977",
"createdAt": 2020-04-23T02:01:20.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
],
"text": "3–> Olivia to Mike",
"user": Object {
"_id": "lTONqS9O00PhkxwHD2EYs05EMwu2",
"avatar": "123",
},
},
Object {
"_id": "fae07391-9968-432a-8a39-0c1be0d7e9ac",
"createdAt": 2020-04-23T01:51:41.000Z,
"index": 0,
"key": "cid-1710824786",
"receiver": Array [
"lTONqS9O00PhkxwHD2EYs05EMwu2",
],
"text": "1–> mike to Olivia",
"user": Object {
"_id": "OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
"avatar": "123",
},
},
],
The messages are still coming in out of order so I am sure I am writing the sort function incorrectly. I am going through these tutorials and docs and it seems to be correct....
https://www.geeksforgeeks.org/sort-an-object-array-by-date-in-javascript/
https://flaviocopes.com/how-to-sort-array-by-date-javascript/
How to sort an array by a date property
I have also tried explicitly writing out the function like:
let unorderedmessage = realtime.concat(messages);
unorderedmessage.sort(function(a, b) {
return new Date(b.createdAt) - new Date(a.createdAt);
});
setMessages(unorderedmessage);
but still no luck. Can anyone see what I am doing wrong?
Works like a charm for me: https://playcode.io/583725/
Cannot be the issue in your Object variable definition?
You don't need to specify Object, this is enough:
const myNewObject = {firstKey: 'firstValue', secondKeys: 'secondValue'}
But if you do, you have to create it with new keyword:
const myNewObject = new Object {firstKey: 'firstValue', secondKeys: 'secondValue'}

Remove objects from nested array using Lodash

I have the following JSON structure:
{
"id": 123,
"shops": [
{
"shopId": 456,
"products": [
{
"productId": 10001,
"name": "abc",
"state": "active"
},
{
"productId": 10002,
"name": "def",
"state": "expired"
}
]
},
{
"shopId": 789,
"products": [
{
"productId": 20001,
"name": "qrt",
"state": "expired"
},
{
"productId": 20002,
"name": "jbf",
"state": "active"
}
]
}
]
}
I want to remove all products from each shop where the product does not have certain properties.
If I covert it to a flat map then I can do it fine, but then I lose the outer object as I just have an array with all the products that haven't been removed in.
_(shopJson.shops).map('products').flatten().map(x => {if(x.state === 'active'){return x}}).compact().value()
I tried the following but just end up with an empty array:
_(shopJson.shops).map('products').filter(x => x.state === 'active').value()
I also tried using _.reduce() and _.transform() but can't get it to work
The final JSON should look like:
{
"id": 123,
"shops": [
{
"shopId": 456,
"products": [
{
"productId": 10001,
"name": "abc",
"state": "active"
}
]
},
{
"shopId": 789,
"products": [
{
"productId": 20002,
"name": "jbf",
"state": "active"
}
]
}
]
}
You don't really need lodash for this. You can just use Array.prototype.map and Array.protype.filter (and also some spread syntax to shallow merge object properties):
const data = {id:123,shops:[{shopId:456,products:[{productId:10001,name:"abc",state:"active"},{productId:10002,name:"def",state:"expired"}]},{shopId:789,products:[{productId:20001,name:"qrt",state:"expired"},{productId:20002,name:"jbf",state:"active"}]}]};
const result = {
...data,
shops: data.shops.map((shop) => ({
...shop,
products: shop.products.filter((product) => product.state === 'active'),
})),
};
console.log(result);
EDIT: As #Deykun pointed out, if you want to ignore shops that don't have any active products, you can filter shops out using Array.prototype.some in a filter:
const data = {id:123,shops:[{shopId:456,products:[{productId:10001,name:"abc",state:"active"},{productId:10002,name:"def",state:"expired"}]},{shopId:789,products:[{productId:20001,name:"qrt",state:"expired"},{productId:20002,name:"jbf",state:"expired"}]}]};
const result = {
...data,
shops: data.shops
.filter((shop) => shop.products.some((product) => product.state === 'active'))
.map((shop) => ({
...shop,
products: shop.products.filter((product) => product.state === 'active')
}))
};
console.log(result);

mapping JSON Data reverse?

I got stuck on a maybe simple task, but could not find any solution.
I have some JSON Data - lets say:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"]
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"]
}, {
"_id": 3,
"type": "department",
"Name": "Marketing"
}, {
"_id": 4,
"type": "department",
"Name": "Sales"
}]
As I learned here it is quite simple to get all the persons and the departments they work for together using a map array for the departments.
Then I can map the corresponding department to the Person and receive something like:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"],
"Readable": ["Marketing", "Sales"]
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"],
"Readable": ["Sales"]
}]
But for another interface I need the data "the other way round" e.g.
[{
"_id": 3,
"type": "department",
"Name": "Marketing",
"employees": [
"Hans", "Michael"
]
}, {
"_id": 4,
"type": "department",
"Name": "Sales",
"employees": [
"Hans"
]
}]
Is there any decent way to achieve this structure? Two days of trying didn't get me anywhere...
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"] }, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"] }, { "_id": 3, "type": "department", "Name": "Marketing" }, { "_id": 4, "type": "department", "Name": "Sales" }];
var departments = [],
persons = [];
data.forEach(e => {
if (e.type === "person") {
persons.push(e);
} else if (e.type === "department") {
departments.push(e);
e.employees = [];
}
});
departments.forEach(d => {
var workers = persons.filter(p => p.WorksFor.indexOf(d._id.toString()) > -1)
/*.map(p => p.Name)*/ // add this if you only need the name instead of the complete "person"
d.employees = d.employees.concat(workers);
});
console.log(JSON.stringify(departments, null, 4));
You can try something like this:
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}]
var ignoreDept = ['person'];
var result = data.reduce(function(p,c,i,a){
if(ignoreDept.indexOf(c.type) < 0){
c.employees = a.reduce(function(arr,emp){
if(emp.WorksFor && emp.WorksFor.indexOf(c._id.toString()) > -1){
arr.push(emp.Name)
}
return arr;
},[]);
p.push(c);
}
return p;
}, []);
console.log(result)
The solution using Array.prototype.filter() and Array.prototype.forEach() functions:
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}],
// getting separated "lists" of departments and employees(persons)
deps = data.filter(function(o){ return o.type === "department"; }),
persons = data.filter(function(o){ return o.type === "person"; });
deps.forEach(function (d) {
d['employees'] = d['employees'] || [];
persons.forEach(function (p) {
if (p.WorksFor.indexOf(String(d._id)) !== -1) { // check the `id` coincidence between the employee and the department
d['employees'].push(p.Name);
}
});
});
console.log(deps);
You could use a hash table and a single loop for each array.
Methods:
Array#reduce for iterating an array and returning the result,
Array#forEach for looping the inner array WorksFor,
Object.create(null) to generate an object without any prototypes,
some other pattern, like a closure over hash and
the use of logical OR || for checking a falsy value and taking an object as default.
hash[b] = hash[b] || { _id: b, employees: [] };
var data = [{ _id: 1, type: "person", Name: "Hans", WorksFor: [3, 4] }, { _id: 2, type: "person", Name: "Michael", WorksFor: [3] }, { _id: 3, type: "department", Name: "Marketing" }, { _id: 4, type: "department", Name: "Sales" }],
result = data.reduce(function (hash) {
return function (r, a) {
if (a.type === 'person') {
a.WorksFor.forEach(function (b) {
hash[b] = hash[b] || { _id: b, employees: [] };
hash[b].employees.push(a.Name);
});
}
if (a.type === 'department') {
hash[a._id] = hash[a._id] || { _id: b, employees: [] };
hash[a._id].type = a.type;
hash[a._id].Name = a.Name;
r.push(hash[a._id]);
}
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a way you can get the first mapping. I've added some comments so you can follow along, and with it I hope you can find the answer to your second problem.
// First, let's get just the items in this array that identify persons
// I've called this array "data"
data.filter(x => x.type === 'person')
// Now let's map over them
.map(person =>
// We want all of the data associated with this person, so let's
// use Object.assign to duplicate that data for us
Object.assign({}, person, {
// In addition, we want to map the ID of the WorksFor array to the Name
// of the corresponding department. Assuming that the _id key is unique,
// we can due this simply by mapping over the WorksFor array and finding
// those values within the original array.
Readable: person.WorksFor.map(wfId =>
// Notice here the parseInt. This will not work without it due to
// the type difference between WorksFor (string) and _id (integer)
data.find(d => d._id === parseInt(wfId)).Name
)
})
);
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}];
var dep = {};
data.forEach(e => (e.type === 'person' && e.WorksFor.forEach(d => dep[d]? dep[d].push(e.Name): dep[d] = [e.Name])));
data.forEach(e => (e.type == 'department' && (e.employees = dep[e._id] || [])));
data = data.filter(e => e.type == 'department');
console.log(data);

Categories

Resources