linq.js Group By then Group By, How can it be achieved? - javascript

I want something that would result in this
[{
firstName: "Sam",
lastName: "Smith"
}, {
firstName: "Sam",
lastName: "Doe"
}, {
firstName: "Sam",
lastName: "Doe"
}, {
firstName: "Sam",
lastName: "Joe"
}]
Being something like this, with the exception of the number of columns to group with which is not fixed and the order of the columns as well
[{
"Sam": [{
"Smith": [{
firstName: "Sam",
lastName: "Smith"
}]
}, {
"Doe": [{
firstName: "Sam",
lastName: "Doe"
}, {
firstName: "Sam",
lastName: "Doe"
}]
}, {
"Joe": [{
firstName: "Sam",
lastName: "Joe"
}]
}]
}]
I want to be able to build something like the following photo demonstrates
I tried several times but i can't get a grasp on it, please help me :).

I propose a different output structure. Your structure seems convenient at first glance, but in further processing it will prove unnecessarily difficult to handle.
I would suggest this generic structure:
[
{
key: "group 1",
items: [{
key: "group 1.1",
items: [ {}, {}, {} ]
}, {
key: "group 1.2",
items: [ {}, {} ]
}]
}, {
key: "group 2",
items: [{
key: "group 2.1",
items: [ {}, {}, [}, {} ]
}, {
key: "group 2.2",
items: [ {} ]
}]
}
]
You can create a structure like this relatively easily:
var grouped = Enumerable.From(input).GroupBy("$.firstName", "", function(key, e) {
return {
key: key,
items: e.GroupBy("$.lastName", "", function (key, e) {
return {
key: key,
items: e.ToArray()
};
}).ToArray()
};
}).ToArray();
when applied to this input:
var input = [{
firstName: "Sam",
lastName: "Smith"
}, {
firstName: "Sam",
lastName: "Doe"
}, {
firstName: "Sam",
lastName: "Doe"
}, {
firstName: "Sam",
lastName: "Joe"
},{
firstName: "John",
lastName: "Joe"
}];
results in
[
{
"key": "Sam",
"items": [
{
"key": "Smith",
"items": [
{
"firstName": "Sam",
"lastName": "Smith"
}
]
},
{
"key": "Doe",
"items": [
{
"firstName": "Sam",
"lastName": "Doe"
},
{
"firstName": "Sam",
"lastName": "Doe"
}
]
},
{
"key": "Joe",
"items": [
{
"firstName": "Sam",
"lastName": "Joe"
}
]
}
]
},
{
"key": "John",
"items": [
{
"key": "Joe",
"items": [
{
"firstName": "John",
"lastName": "Joe"
}
]
}
]
}
]
Edit: To allow dynamically configurable grouping and ordering, a more advanced approach must be taken:
// Enumerable, definition => Enumerable
function applyOrder(items, definition) {
var i, prop, prefix, suffix, orderFunc;
if (!items) return;
if (!definition) return items;
for (i = 0; i < definition.length; i++) {
// definition[i] is either "propertyName" or "propertyName DESC"
prop = (definition[i] + " ").split(" ");
prefix = i === 0 ? "OrderBy" : "ThenBy";
suffix = prop[1].toUpperCase() === "DESC" ? "Descending" : "";
orderFunc = prefix + suffix;
items = items[orderFunc]("$." + prop[0]);
}
return items;
}
// Enumerable, definition => Enumerable
function applyGroup(items, definition) {
if (!items) return;
if (!definition) return items;
items = applyOrder(items, definition.order);
if (!definition.group) return items;
return items.GroupBy("$." + definition.group, "", function (key, e) {
return {
group: definition.group,
key: key,
items: applyGroup(e, definition.then).ToArray()
};
});
}
// Array, definition => Array
function applyStructure(items, definition) {
if (!items) return;
if (!definition) return items;
return applyGroup(Enumerable.From(items), definition).ToArray();
}
used like this:
var result = applyStructure(companies, {
group: "country",
order: ["country"],
then: {
group: "city",
order: ["city"],
then: {
order: ["companyName DESC"]
}
}
});
live at: http://jsfiddle.net/Tomalak/xth6ayuo/

Related

How to match more than one property of an object

I can match a single property easy enough
var peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" },
{ "name": "john", "dinner": "pie" }
];
$.each(peoples, function(i, val) {
$.each(val, function(key, name) {
if (name === "john")
console.log(key + " : " + name);
});
});
But since there are 2 johns how do I match a particular one (eg the john that like sushi) and then return the whole matched object (in json)? I tried adding another condition to the if statement but that didn't seem to work.
Thanks
you can use find to check exact match
var peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" },
{ "name": "john", "dinner": "pie" }
];
var filteredResult = peoples.find(val => val.name ==="john" && val.dinner==="sushi");
console.log(filteredResult)
I don't know the context, but there could be two john and both with the dinner property set to pie. I would suggest using id for each entry in the array. If the array you are working with is the one you list, you could project/transform it using map before you perform searches. For example
const people = [
{ name: "bob", dinner: "pizza" },
{ name: "john", dinner: "sushi" },
{ name: "larry", dinner: "hummus" },
{ name: "john", dinner: "pie" },
];
const peopleList = people.map((person, id) => ({ id, ...person }));
console.log(peopleList);
// You could start from here to search by id
Consider the following.
var peoples = [{
"name": "bob",
"dinner": "pizza"
},
{
"name": "john",
"dinner": "sushi"
},
{
"name": "larry",
"dinner": "hummus"
},
{
"name": "john",
"dinner": "pie"
}
];
$.each(peoples, function(i, val) {
if (val.name == "john" && val.dinner == "sushi") {
console.log("Persons[" + i + "]." + Object.keys(val)[0] + ": " + val.name);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This iterates all the items and compares elements of each.
_.filter by lodash
You can use filter method by lodash
Iterates over elements of collection, returning an array of all elements predicate returns truthy for.The predicate is invoked with three arguments: (value, index|key, collection).It return a new array
https://lodash.com/docs/4.17.15#filter
Example for filter usage on lodash
var users = [{
'user': 'barney',
'age': 36,
'active': true
},
{
'user': 'fred',
'age': 40,
'active': false
},
{
'user': 'fred',
'age': 39,
'active': true
}
];
console.log("matches:", _.filter(users, function(o) {
return !o.active;
}));
// => [{ active: true, age: 36, user: "barney"}]
// The `_.matches` iteratee shorthand.
console.log("_.matches` iteratee", _.filter(users, {
'user': 'fred',
'active': true
}));
// => [{ active: true, age: 39, user: "fred"}]
// The `_.matchesProperty` iteratee shorthand.
console.log("matchs poperty", _.filter(users, ['active', false]));
// => objects for ['fred']
// The `_.property` iteratee shorthand.
_.filter(users, 'active');
// => objects for ['barney']
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
_.where by underscore.js
You can also use where method of underscore.js
Looks through each value in the list, returning an array of all the values that
matches the key-value pairs listed in properties.
_.where(list, properties)
Example of _.where usage
_.where(listOfPlays, {author: "Shakespeare", year: 1611});
You can basicaly use filter method in plain vanilla javascript
var peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" },
{ "name": "john", "dinner": "pie" }
];
var dinner = peoples.filter(e=>e.name ==="john" && e.dinner==="sushi");
console.log(dinner)
You may also use jquery grep
var peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" },
{ "name": "john", "dinner": "pie" }
];
var dinner = $.grep(peoples, function(people) {
return people.name === "john" && people.dinner === "sushi";
});
console.log(dinner)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Find vs filter
var peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" },
{ "name": "john", "dinner": "pie" }
];
var filterDinner = peoples.filter(e=>e.name ==="john" && e.dinner==="sushi");
// return all matching results
console.log('filter dinner -:', filterDinner);
var findDinner = peoples.find(e=>e.name ==="john" && e.dinner==="sushi");
//returns the first matching rslt
console.log('find dinner -:', findDinner);
Find was not recommended because it return the first matching result and suppose we have more matching results they are missed out.
You could set up a function to define your search terms then use Array.filter:
const peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" },
{ "name": "john", "dinner": "pie" }
];
searchTerms = (person) => {
return person.name === "john" && person.dinner === "sushi";
}
console.log(peoples.filter(searchTerms));
// [{ "name": "john", "dinner": "sushi" }]

Accessing an object property from outside scope

So I have 4 jsons with that looks like this:
{
"group": "A",
"id": "50"
"person": [
{
"name": 'Joe',
"age": '29'
},
{
"name": 'Jessie',
"age": '27'
}
]
}
I used this function to create an array with all the people from 4 different json's files.
list.forEach(list => {
list.person.forEach(person => {
peopleArray.push(person);
});
})
The problem is, when I pick a position from that array, I want to be able to access the group and the ID as well for example:
console.log(peopleArray[1].group);
Is that possible? Or I would have to those values inside the person?
Just include those values in the person object
const data = {
group: "A",
id: "50",
person: [
{
name: 'Joe',
age: '29'
},
{
name: 'Jessie',
age: '27'
}
]
}
data.person.map(obj => ({...obj, group: data.group, groupId: data.id}))
The result is:
[
{
age: "29",
group: "A",
groupId: "50",
name: "Joe"
},
{
age: "27",
group: "A",
groupId: "50",
name: "Jessie"
}
]

Loop through nested json array to create new array

I am working on a lambda function that GETs data from one API and POSTs it to another. The data is a list of contacts with properties, e.g. first name, last name, email, etc.
The JSON output contains too many properties that I don't need. See below code example (actual code contains many more properties and nested arrays/objects).
{
"contacts": [
{
"addedAt": 1532803458796,
"vid": 101
}
],
"merge-audits": [],
"properties": {
"first-name": {
"value":"hello"
},
"last-name": {
"value":"there"
},
"email": {
"value":"hello#there.com"
}
...
...
}
How can I loop through each JSON object to create a new, simpler JSON array like the following:
[
{
"email": "example#example.com",
"first_name": "",
"last_name": "User"
},
{
"email": "example2#example.com",
"first_name": "Example",
"last_name": "User"
}
]
Thanks in advance for your help.
try
json.map( x => ({
email: x.properties.email.value,
first_name: x.properties['first-name'].value,
last_name: x.properties['last-name'].value,
}));
let json = [
{
"contacts": [{
"addedAt": 1532803458796,
"vid": 101
}],
"merge-audits": [],
"properties": {
"first-name": {
"value": "hello"
},
"last-name": {
"value": "there",
},
"email": {
"value": "hello#there.com"
}
}
},
{
"contacts": [{
"addedAt": 1532803458796,
"vid": 101
}],
"merge-audits": [],
"properties": {
"first-name": {
"value": "Tom"
},
"last-name": {
"value": "Smith",
},
"email": {
"value": "tom#smith.com"
}
}
}
]
let r = json.map(x => ({
email: x.properties.email.value,
first_name: x.properties['first-name'].value,
last_name: x.properties['last-name'].value,
}));
console.log(r);
You could use a destructuring assignment for the object and short hand properties for the mapping.
var data = [{ contacts: [{ addedAt: 1532803458796, vid: 101 }], "merge-audits": [], properties: { "first-name": { value: "hello" }, "last-name": { value: "there" }, email: { value: "hello#there.com" } } }],
result = data.map(({ properties: {
'first-name': { value: first_name },
'last-name': { value: last_name },
email: { value: email }
} }) => ({ first_name, last_name, email }));
console.log(result);

How to merge children in multiple JSON objects?

I have the following JavaScript object
[
{
"familyName": "Smith",
"children": [
{ "firstName": "John" },
{ "firstName": "Mike" }
]
},
{
"familyName": "Williams",
"children": [
{ "firstName": "Mark" },
{ "firstName": "Dave" }
]
},
{
"familyName": "Jones",
"children": [
{ "firstName": "Mary" },
{ "firstName": "Sue" }
]
}
]
I’d like to create an array of all children i.e.
[
{ "FirstName": "John" },
{ "FirstName": "Mike" },
{ "FirstName": "Mark" },
{ "FirstName": "Dave" },
{ "FirstName": "Mary" },
{ "FirstName": "Sue" }
]
I am using jQuery.
I have looked at posts that describe merging or concatenating arrays but not those of child arrays: e.g. Merge/flatten an array of arrays in JavaScript?
I believe I could loop through the families and add the children arrays but suspect that there is a 'one-liner' for this?
I tested in the console:
//The families(duh)
const families = [
{
"familyName": "Smith",
"children": [
{ "firstName": "John" },
{ "firstName": "Mike" }
]
},
{
"familyName": "Williams",
"children": [
{ "firstName": "Mark" },
{ "firstName": "Dave" }
]
},
{
"familyName": "Jones",
"children": [
{ "firstName": "Mary" },
{ "firstName": "Sue" }
]
}
]
//Just flatten the children:
var children = [].concat.apply([], families.map(family => family.children));
//Outputs
console.log(children);
A solution without jQuery would be to use reduce to extract children from their families (sounds a bit rough, sorry for that).
families.reduce(function(list, family){
return list.concat(family.children);
}, []);
You can do this by using $.map:
var a = [
{
"familyName": "Smith",
"children": [
{ "firstName": "John" },
{ "firstName": "Mike" }
]
},
{
"familyName": "Williams",
"children": [
{ "firstName": "Mark" },
{ "firstName": "Dave" }
]
},
{
"familyName": "Jones",
"children": [
{ "firstName": "Mary" },
{ "firstName": "Sue" }
]
}
]
console.log($.map(a, function(it){
return it.children;
}));
// Or ES6
$.map(a, it => it.children);
Result:
[
{
"firstName":"John"
},
{
"firstName":"Mike"
},
{
"firstName":"Mark"
},
{
"firstName":"Dave"
},
{
"firstName":"Mary"
},
{
"firstName":"Sue"
}
]
Try with Array#forEach method .then push the children object with new array
var families = [ { "familyName": "Smith", "children": [ { "firstName": "John" }, { "firstName": "Mike" } ] }, { "familyName": "Williams", "children": [ { "firstName": "Mark" }, { "firstName": "Dave" } ] }, { "familyName": "Jones", "children": [ { "firstName": "Mary" }, { "firstName": "Sue" } ] } ]
var children = [];
families.forEach(family => family.children.forEach(child => children.push(child)));
console.log(children);

How to get the Uniq objects Using javascript or lodash

i am having the Array of objects like this
var result={
"employees": [
{
"_id": "5796e7a27d075bd0453b7751",
"firstName": "Test4",
"schemaName": "Employee"
},
{
"_id": "5796e78e7d075bd0453b774f",
"firstName": "Test 3",
"schemaName": "Employee"
},
{
"_id": "5790b203df5ad69025e8a20b",
"email": "df#gmail.com",
"schemaName": "Employee"
},
{
"_id": "577f69cc789df5ec1e995513",
"firstName": "Jeevan",
"email": "ddd#asd.com",
"schemaName": "Employee"
},
{
"_id": "577f69cc789df5ec1e995513",
"firstName": "Chethan",
"email": "ddd#asd.com",
"schemaName": "Employee"
}
]
};
};
but i want uniq objects by email. i am using lodash uniq but its Not giving proper Result. here i tried this code.
var combined=result.employees.map(function(employee){
employee.schemaName='Employee';
return employee;
});
combined = _.uniq(combined, 'email');
console.log(combined);
The Result is coming like this.
[ { _id: '5796e7a27d075bd0453b7751',
firstName: 'Test4',
schemaName: 'Employee' },
{ _id: '5790b203df5ad69025e8a20b',
email: 'df#gmail.com',
schemaName: 'Employee' },
{ _id: '577f69cc789df5ec1e995513',
firstName: 'Jeevan',
email: 'ddd#asd.com',
schemaName: 'Employee' } ]
i want the objects which are not having email ids and i want only objects which are unique emailid's can anybody help me on this. I want the Result contain the objects Which are not having email id also. The Result should be like this.
[ { _id: '5796e7a27d075bd0453b7751',
firstName: 'Test4',
schemaName: 'Employee' },
{ _id: '5796e78e7d075bd0453b774f',
firstName: 'Test3',
schemaName: 'Employee' },
{ _id: '5790b203df5ad69025e8a20b',
email: 'df#gmail.com',
schemaName: 'Employee' },
{ _id: '577f69cc789df5ec1e995513',
firstName: 'Jeevan',
email: 'ddd#asd.com',
schemaName: 'Employee' } ]
This could make it too.
_.uniqBy(result.employees, function(employee){return employee.email || employee._id;});
I would recommend the use of _.uniqWith for this with your own comparator.
var result = {
"employees": [
{
"_id": "5796e7a27d075bd0453b7751",
"firstName": "Test4",
"lastName": "T",
"__v": 0,
"schemaName": "Employee"
},
{
"_id": "5796e78e7d075bd0453b774f",
"firstName": "Test 3",
"lastName": "T",
"__v": 0,
"schemaName": "Employee"
},
{
"_id": "5796e77e7d075bd0453b774d",
"firstName": "Test 2",
"lastName": "T",
"__v": 0,
"documents": [],
"schemaName": "Employee"
},
{
"_id": "5796e7707d075bd0453b774b",
"firstName": "Test1",
"lastName": "T",
"__v": 0,
"schemaName": "Employee"
},
{
"_id": "5790b203df5ad69025e8a20b",
"firstName": "Ganesh",
"lastName": "dsf",
"__v": 0,
"email": "df#gmail.com",
"schemaName": "Employee"
},
{
"_id": "577f69cc789df5ec1e995513",
"firstName": "Jeevan",
"__v": 0,
"email": "fs#asf.com",
"schemaName": "Employee"
},
{
"_id": "577f69cc789df5ec1e995513",
"firstName": "Chethan",
"__v": 0,
"email": "fs#asf.com",
"schemaName": "Employee"
}
]
};
// Create a lodash chain from the employees.
combined = _.uniqWith(result.employees, function(e1, e2){
return e1.email && e1.email === e2.email;
});
console.log(combined);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.0/lodash.min.js"></script>
I'm using a deepEquals algorithm so this code becomes more general. If you want to check only by email, just change the equals function below.
const equals =
// Naïve deepEquals, only for demo. Doesn't work if keys orders vary.
(obj1, obj2) => JSON.stringify(obj1) === JSON.stringify(obj2);
// A real deepEquals:
// https://www.npmjs.com/package/fast-deep-equal
const uniq = (el1, index1, array) =>
array.every((el2, index2) => index1 <= index2 || !equals(el1, el2));
[{ a: 1, b: 2 }, { c: 3 }, { a: 1, b: 2 }, { d: 4 }, { a: 1, b: 2 }].filter(uniq);
// Result: [ { a: 1, b: 2 }, { c: 3 }, { d: 4 } ]

Categories

Resources