Find the latter date in an object - javascript

I need iterate specific objects in an object, and find the object with latter Date.
Here is example of my object:
var o = {
"data": [
{
"id": 2,
"category": "test1",
"parents": [
{
"id": 31,
"children": [
{
"firstName": "Steve",
"lastName": "Martin",
"created": "2018-04-06T22:00:00.000Z"
},
{
"firstName": "Steve2",
"lastName": "Martin2",
"created": "2016-02-10T23:00:00.000Z"
}
]
},
{
"id": 31,
"children": [
{
"firstName": "Julia",
"lastName": "Robbery",
"created": "2015-01-06T23:00:00.000Z"
},
{
"firstName": "Nikol",
"lastName": "Surachenko",
"created": "2017-04-06T22:00:00.000Z"
},
{
"firstName": "Nikol",
"lastName": "Surachenko",
"created": "2011-06-05T22:00:00.000Z"
}
]
}
]
}
]
}
I tried this:
var latter = null;
for (var i = 0; i < o.data[0].parents.length; i++) {
for (var j = 0; j < o.data[0].parents[i].children.length; j++) {
if (latter == null || moment(latter) < moment(o.data[0].parents[i].children[j].created))
latter=o.data[0].parents[i].children[j].created;
}
}
Can you tell me if exist some prettier way? For example with lambda, etc.?
Thanks in advice.

"pretty" is subjective, but in my opinion with lodash you could write it in a bit cleaner way:
mostRecent = _.max(
_.flatMap(
_.get(o, 'data.0.parents'),
'children'),
'created')
If lodash is not an option, you can roll out your own ad-hoc microframework:
let get = p => o => o[p];
let flatMap = (a, f) => [].concat(...a.map(f));
let max = (a, f) => a.map(x => [x, f(x)]).reduce((m, p) => m[1] > p[1] ? m : p)[0];
mostRecent = max(
flatMap(o.data[0].parents, get('children')),
get('created')
)

Using for-loops and compare dates.
This approach downstreams into the whole object to get the right object.
var o = { "data": [{ "id": 2, "category": "test1", "parents": [{ "id": 31, "children": [{ "firstName": "Steve", "lastName": "Martin", "created": "2018-04-06T22:00:00.000Z" }, { "firstName": "Steve2", "lastName": "Martin2", "created": "2016-02-10T23:00:00.000Z" } ] }, { "id": 31, "children": [{ "firstName": "Julia", "lastName": "Robbery", "created": "2015-01-06T23:00:00.000Z" }, { "firstName": "Nikol", "lastName": "Surachenko", "created": "2017-04-06T22:00:00.000Z" }, { "firstName": "Nikol", "lastName": "Surachenko", "created": "2011-06-05T22:00:00.000Z" } ] } ] }] }
var result = {};
for (var obj of o.data) {
for (var p of obj.parents) {
for (var c of p.children) {
result = !result.created || Date.parse(c.created) > Date.parse(result.created) ? c : result;
}
}
}
console.log(result);

You might do it a bit more functional:
const result = o.data[0].parents.reduce((res, {children}) => res.concat(children), [])
.reduce((old, curr) => Date(old.created) > Date(curr.created) ? old : curr);

Related

Flattening json with an key exclusion list

I need to flatten the json, but want to consider an exclusion_keys_array list which are not to be processed/added to the list
for example
if I have an exclusion_keys_array = ["addresses.metadata", "pageToken"]
//only metadata of addresses will be skipped (second level skip)
if I have an exclusion_keys_array = ["metadata", "pageToken"]
//metadata of parent json will be skipped (top level key skip)
How do I flatten a JSON using an exclusion array?
Code source: Dynamically generate a 2d array from JSON with varying columns
var exlusion_list = ["metadata", "meta", "pageToken"];
var crowds = [{
"name": [{
"firstName": "John",
"middleName": "Joseph",
"lastName": "Briggs",
}],
"addresses": [{
"type": "home",
"poBox": "111",
"city": "City1",
"postalCode": "1ER001",
"country": "USA",
}, {
"type": "work",
"poBox": "222",
"city": "City2",
"region": "Region2",
"postalCode": "1ER002",
}],
"photos": [{
"url": "photo.org/person1",
"default": true,
}, {
"url": "imagur.org/person1",
"default": true,
}],
"metadata": [{
"meta-id": "1234",
}],
}, {
"name": [{
"firstName": "Bill",
"lastName": "Thatcher",
}],
"addresses": [{
"type": "home",
"city": "City3",
"region": "Region3",
"postalCode": "1ER003",
"country": "USA",
}, {
"type": "work",
"poBox": "444",
"region": "Region4",
"postalCode": "1ER004",
}, {
"poBox": "555",
"region": "Region5",
"postalCode": "1ER005",
}],
"metadata": [{
"meta-id": "1234",
}],
}];
function flatten(obj, res = {}, key = '') {
let add = (d, s) => key ? key + d + s : s;
if (Array.isArray(obj)) {
obj.forEach((v, n) => flatten(v, res, add(' #', n + 1)));
} else if (typeof obj === 'object') {
Object.entries(obj).forEach(([k, v]) => flatten(v, res, add(': ', k)));
} else {
res[key] = obj;
}
return res;
}
let flats = crowds.map(obj => flatten(obj));
function combineKeys(objs) {
let keys = objs.reduce((k, obj) => k.concat(Object.keys(obj)), []);
return [...new Set(keys)];
}
let keys = combineKeys(flats);
let table = flats.map(f => keys.map(k => f[k] ?? ''));
table.unshift(keys);
console.log({ table });
// document.write(JSON.stringify(table));
.as-console-wrapper { min-height: 100%!important; top: 0; }
// .as-console-wrapper { min-height: 70%!important; bottom: 0; }
A quick fix would be filter the keys like below. I think there is a more efficient way to do it but I didn't look into the codes too deep.
let keys = combineKeys(flats).filter(
key => !exlusion_list.includes(key.split(":")[0].split(" ")[0])
);

Slicing an Array and producing an object from it

I have an array and it looks as follow:
[
{
"DT_RowId": "row_4758",
"companies": {
"id": 23,
"email": null,
"name": "test"
},
"USERS": {
"UserId": 23
}
},.....
]
How do I slice it and get only "companies": and the result as follows:
[
{
"id": 23,
"email": null,
"name": "test"
},.....
]
to clear some issues I have added the function in which I'm using data.map
fn.loadData = function (data) {
var dataKeys = Object.keys(data);
console.log(data)// 'data' is an object
console.log(data.map(x => x.companies)) ///data.map not a function error
var infiniteList = document.getElementById('infinite-list');
infiniteList.delegate = {
createItemContent: function (i) {
return ons._util.createElement(
'<ons-list-item modifier="chevron" tappable>' + data[dataKeys[i]].name + '</ons-list-item>'
);
},
countItems: function () {
return Object.keys(data).length;
}
};
infiniteList.refresh();
}
as comments told you to do:
const data = [
{
"DT_RowId": "row_4758",
"companies": {
"id": 23,
"email": null,
"name": "test"
},
"USERS": {
"UserId": 23
}
},
{
"DT_RowId": "row_3758",
"companies": {
"id": 24,
"email": null,
"name": "test3"
},
"USERS": {
"UserId": 24
}
},]
console.log(data.map(obj=>obj.companies))
This worked:
const newArray = [];
for (let i = 0; i < companyArray.length; i++) {
newArray.push(companyArray[i].companies);
}
Thanks, everyone

How to compare two objects with lodash and return new object?

Here are two objects I need to compare and return specific values from object1 if found in object2.
object1 = {
"body": {
"items": [
{
"data": {
"name": "Smith",
"status": "Ready",
"userinfo": [
{
"dob": "01/01/2000",
"nickname": "Joe"
}
]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
},
{
"data": {
"name": "Luke",
"status": "Ready",
"userinfo": [
{
"dob": "01/01/2001",
"nickname": "LL"
}
]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
}
]
}
}
Object2 is even simple one:
object2 = {
"items": [
{
"name": "Smith",
"status": "Ready"
},
{
"name": "Luke",
"status": "Ready"
}
]
}
So if Object1 body.items[x].data.name found in Object2 items.name then finally I need to get new object like this:
object3 = {{name: "Smith", status: "Ready"}, {name: "Luke", status: "Ready"}}
You can use filter and find:
var obj1 = {
"body": {
"items": [{
"data": {
"name": "Smith",
"status": "Ready",
"userinfo": [{
"dob": "01/01/2000",
"nickname": "Joe"
}]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
},
{
"data": {
"name": "Luke",
"status": "Ready",
"userinfo": [{
"dob": "01/01/2001",
"nickname": "LL"
}]
},
"workinfo": {
"company": "mycompany",
"address": "101 Main str."
}
}
]
}
}
var obj2 = {
"items": [{
"name": "Smith",
"status": "Ready"
},
{
"name": "Luke",
"status": "Ready"
}
]
}
var output = obj2.items.filter(({name}) => obj1.body.items.find(({data}) => name === data.name))
console.log(output)
Filter will return all the objects that pass the find condition, that is, if the name is found in obj1
You can use _.intersectionWith() to return items from obj2, that their name equals data.name in obj2 items:
const obj1 = {"body":{"items":[{"data":{"name":"Smith","status":"Ready","userinfo":[{"dob":"01/01/2000","nickname":"Joe"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}},{"data":{"name":"Luke","status":"Ready","userinfo":[{"dob":"01/01/2001","nickname":"LL"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}}]}}
const obj2 = {"items":[{"name":"Smith","status":"Ready"},{"name":"Luke","status":"Ready"}]}
const result = _.intersectionWith(obj2.items, obj1.body.items,
(a, b) => _.get(a, 'name') === _.get(b, 'data.name')
)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
With ES6 this is an easy task with Array.filter and Array.some:
const obj1 = {"body":{"items":[{"data":{"name":"Smith","status":"Ready","userinfo":[{"dob":"01/01/2000","nickname":"Joe"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}},{"data":{"name":"Luke","status":"Ready","userinfo":[{"dob":"01/01/2001","nickname":"LL"}]},"workinfo":{"company":"mycompany","address":"101 Main str."}}]}}
const obj2 = {"items":[{"name":"Smith","status":"Ready"},{"name":"Luke","status":"Ready"}]}
const r = obj2.items.filter(x => obj1.body.items.some(y => y.data.name == x.name))
console.log(r)
Since you have the objects in the correct layout in obj2 you can start from there and filter them against obj1.

Resolve References in JSON : Javascript / JSON

I have the following sample JSON coming from a server. Duplicate objects are being internally referred to by an id (see the JSON below).
[
{ "id": 1,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent#gmail.com"
},
{ "id": 2,
"agent": 1, // here I want the full object and not the Id
"user":"agent1#gmail.com"
}
]
Question:
How do I resolve the objects referred to in this fashion given a random JSON object?
(For instance, for the sample JSON above, I will have the below output:)
[
{ "id": 1,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent#gmail.com"
},
{ "id": 2,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent1#gmail.com"
}
]
Basically a single loop proposal, which collects unresolved links and if found the it replaces the open parts with the object.
var data = [{ "id": 1, "agent": { "id": 1, "firstName": "gghg", "lastName": "gh", "phone": "4543534", "admin": true }, "user": "agent#gmail.com" }, { "id": 2, "agent": 1, "user": "agent1#gmail.com" }];
data.forEach(function (a) {
if (typeof a.agent === 'object') {
this[a.agent.id] = this[a.agent.id] || {};
this[a.agent.id].data = a.agent;
this[a.agent.id].update && this[a.agent.id].update.forEach(function (b) {
b.agent = a.agent;
});
return;
}
this[a.agent] = this[a.agent] || {};
if (this[a.agent].data) {
a.agent = this[a.agent].data;
return;
}
this[a.agent].update = this[a.agent].update || [];
this[a.agent].update.push(a);
}, Object.create(null));
console.log(data);
Edit, a more generic version for unknown property references.
var data = [
{ id: 1, agent: { id: 1, firstName: "gghg", lastName: "gh", phone: "4543534", admin: true }, user: "agent#gmail.com", abc: 2 },
{ id: 2, agent: 1, user: "agent1#gmail.com", abc: { id: 2, text: 'blabla' } },
{ id: 3, agent: { id: 1, firstName: "gghg", lastName: "gh", phone: "4543534", admin: true }, user: "agent#gmail.com" },
];
data.forEach(function (a) {
Object.keys(a).forEach(function (k) {
if (typeof a[k] === 'object' && 'id' in a[k]) {
this[a[k].id] = this[a[k].id] || {};
this[a[k].id].data = a[k];
this[a[k].id].update && this[a[k].id].update.forEach(function (b) {
b[k] = a[k];
});
return;
}
this[a[k]] = this[a[k]] || {};
if (this[a[k]].data) {
a[k] = this[a[k]].data;
return;
}
this[a[k]].update = this[a[k]].update || [];
this[a[k]].update.push(a);
}, this);
}, Object.create(null));
console.log(data);
try this
var data = [
{ "id": 1,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent#gmail.com"
},
{ "id": 2,
"agent": 1, // here I want the full object and not the Id
"user":"agent1#gmail.com"
}
];
var map = {};
//create a map of items by their id
data.forEach( function(obj){ map[ obj.id ] = obj.agent; } );
//iterate the data array and replace agents by their value if their value is a number.
data = data.map( function(obj){
if ( !isNaN( obj.agent ) )
{
obj.agent = JSON.parse( JSON.stringify( map[ obj.agent ] ) );
}
return obj;
});
console.log( data );
I think the only way is to run through the array two times:
UPD:
var arr = [ ... ]; // your list of data
var collectionFields = ['agent', 'someOtherField'];
var collections = {};
// collect all information about agents
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
for (var k = 0; k < collectionFields.length; k++) {
var field = collectionFields[k];
if (typeof collections[field] === 'undefined') {
collections[field] = {};
}
if (typeof item[field] === 'object') {
collections[field][item[field].id] = item[field];
}
}
}
for (var j = 0; j < arr.length; j++) {
for (var k = 0; k < collectionFields.length; k++) {
var field = collectionFields[k];
if (typeof arr[j][field] === 'number') {
arr[j][field] = collections[field][arr[j][field]];
}
}
console.log(arr);
var a = [ { "id": 1, "agent": {"id": 1, "firstName": "gghg", "lastName": "gh", "phone": "4543534",
"admin": true}, "user":"agent#gmail.com"},
{ "id": 2, "agent": 1, "user":"agent1#gmail.com"}];
//on = $.parseJSON(a);
console.log(a);
//nsole.log(bson);
var b=[];
var mapID = [];
for(var key in a) {
console.log(a[key].agent);
b[key] = a[key];
if($.isNumeric(a[key].agent)){
var id = a[key].agent;
b[key].agent = a[mapID[id]].agent;
}
mapID[a[key].id] = key;
}
console.log(b);
check working demo
You can simply define a getter for items which has only the agent ID.
var data = [{ "id": 1, "agent": { "id": 1, "firstName": "gghg", "lastName": "gh", "phone": "4543534", "admin": true }, "user": "agent#gmail.com" }, { "id": 2, "agent": 1, "user": "agent1#gmail.com" }];
console.clear();
data.forEach((hash => d => {
var agent = d.agent;
if (typeof agent === 'number')
Object.defineProperty(d, 'agent', {
get: () => hash[agent]
});
else
hash[agent.id] = agent;
})(Object.create(null)));
console.log(data);

Reformating a JSON tree in node

I'm trying a different approach to my previous question. Basically, I have a JSON object that looks like this:
var data = {
"tree": {
"id": "99842",
"label": "Bill",
"children": [
{
"id": "27878",
"label": "Tom",
"children": []
}
]
},
"index": {
"27878": {
"birthdate": "1/21/1988",
"spouse": "June",
"hometown": "Tulsa, OK"
},
"99842": {
"birthdate": "4/15/1969",
"spouse": "Mary",
"hometown": "Dallas, TX"
}
}
};
As you can see, there are two "top-level" items: a 'tree' object and an 'index' object. I want to parse them together to get this:
{
"rows": [
{
"id": "99842",
"data": [
{
"birthdate": "4/15/1969",
"spouse": "Mary",
"hometown": "Dallas, TX"
}
],
"rows": [
{
"id": "27878",
"data": [
{
"birthdate": "1/21/1988",
"spouse": "June",
"hometown": "Tulsa, OK"
}
],
"rows": []
}
]
}
]
}
It seems like I could do recursion with Q, but it almost seems like overkill and I have a hard time getting my head wrapped around it. I'm thinking through a solution with callbacks but don't quite have it yet. I'd appreciate any help.
Recursion seems perfectly reasonable. Here's one possible solution:
function nestObjects(tree, index) {
var output;
if (tree && index) {
output = {
id: tree.id,
data: index[tree.id],
rows: []
};
if (Array.isArray(tree.children) && tree.children.length) {
for (var i = 0, len = tree.children.length; i < len; i++) {
output.rows.push(nestObjects(tree.children[i], index));
}
}
}
return output;
}
var result = {
rows: [nestObjects(data.tree, data.index)]
};
console.log(result);

Categories