Lodash and merge of Arrays with Key - lodash

I am able to merge objects stored in array fine with lodash but what I need is the find a way to merge based on a key which is part of the object. If I don't use key, the merge is not reliable as when a doc is returned out of order, as it will create an invalid merge. So I hope that there is a way to merge based on a key value, in my case its id.
Here is some sample:
Doc 1
[
{
"id": 123,
"Key1": "Test 1",
"Key3": "Test 0"
},
{
"id": 456,
"Key1": "Test 2",
"Key2": "Test 3"
}
]
Doc 2
[
{
"id": 123,
"Key2": "Test 7",
"Key3": "Test 8"
},
{
"id": 789,
"Key1": "Test 5",
"Key2": "Test 6"
}
]
Based on the simple sample above i am looking for an output like this
[
{
"id": 123,
"Key1": "Test 1",
"Key2": "Test 7",
"Key3": "Test 8"
},
{
"id": 456,
"Key1": "Test 2",
"Key2": "Test 3"
},
{
"id": 789,
"Key1": "Test 5",
"Key2": "Test 6"
}
]

const addKeys = (results, keys) => keys.reduce(
(final, item) => {
const id = item.id;
let current = final.find(i => i.id === id);
if (!current) {
current = { id: id };
final.push(current);
}
Object.keys(item).forEach(key => { current[key] = item[key] });
return final;
}, results
);
console.log(addKeys(
[
{
"id": 123,
"Key1": "Test 1",
"Key3": "Test 0"
},
{
"id": 456,
"Key1": "Test 2",
"Key2": "Test 3"
}
],
[
{
"id": 123,
"Key2": "Test 7",
"Key3": "Test 8"
},
{
"id": 789,
"Key1": "Test 5",
"Key2": "Test 6"
}
]
));

Use flow to create a function. Concat the arrays to a single array, group them by the id, and then map the groups, and merge each group to a single object:
const { flow, concat, partialRight: pr, groupBy, map, merge } = _
const mergeArrays = flow(
concat, // concat to a single array
pr(groupBy, 'id'), // group item by id
pr(map, g => merge({}, ...g)) // merge each group to a single object
)
const arr1 = [{"id":123,"Key1":"Test 1","Key3":"Test 0"},{"id":456,"Key1":"Test 2","Key2":"Test 3"}]
const arr2 = [{"id":123,"Key2":"Test 7","Key3":"Test 8"},{"id":789,"Key1":"Test 5","Key2":"Test 6"}]
const result = mergeArrays(arr1, arr2)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
And a terser version of this solution with lodash/fp:
const { flow, concat, groupBy, map, mergeAll } = _
const mergeArrays = flow(
concat, // concat to a single array
groupBy('id'), // group item by id
map(mergeAll) // merge each group to a single object
)
const arr1 = [{"id":123,"Key1":"Test 1","Key3":"Test 0"},{"id":456,"Key1":"Test 2","Key2":"Test 3"}]
const arr2 = [{"id":123,"Key2":"Test 7","Key3":"Test 8"},{"id":789,"Key1":"Test 5","Key2":"Test 6"}]
const result = mergeArrays(arr1, arr2)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>

Related

How can I check if array has an objects in Postman

I have a response the array with objects like this:
[
{
"id": 1,
"name": "project one"
},
{
"id": 2,
"name": "project two"
},
{
"id": 3,
"name": "project three"
}
]
Have can I check if my responsed array have an object {
"id": 3,
"name": "project three"
} for example?
I am trying to check by this way but it didn't work:
pm.test('The array have object', () => {
pm.expect(jsonData).to.include(myObject)
})
pm.expect(jsonData).to.include(myObject) works for String but not for Object. You should use one of the following functions and compare each property of the object:
Array.filter()
Array.find()
Array.some()
Examples:
data = [
{
"id": 1,
"name": "project one"
},
{
"id": 2,
"name": "project two"
},
{
"id": 3,
"name": "project three"
}
];
let object_to_find = { id: 3, name: 'project three' }
// Returns the first match
let result1 = data.find(function (value) {
return value.id == object_to_find.id && value.name == object_to_find.name;
});
// Get filtered array
let result2 = data.filter(function (value) {
return value.id == object_to_find.id && value.name == object_to_find.name;
});
// Returns true if some values pass the test
let result3 = data.some(function (value) {
return value.id == object_to_find.id && value.name == object_to_find.name;
});
console.log("result1: " + result1.id + ", " + result1.name);
console.log("result2 size: " + result2.length);
console.log("result3: " + result3);
Use one of the ways while asserting in Postman.
you can validate this also using includes after converting it to string using JSON.stringify
pm.expect(JSON.stringify(data)).to.include(JSON.stringify({
"id": 3,
"name": "project three"
}))
Also you can use lodash function some/any:
pm.expect(_.some(data,{
"id": 3,
"name": "project three"
})).to.be.true
https://lodash.com/docs/3.10.1#some
Note: Postman works in a sandbox and only below libraries are suported:
https://learning.postman.com/docs/writing-scripts/script-references/postman-sandbox-api-reference/#using-external-libraries

Vue JS2 find array value by id

How can i get the value by id from a array in vue js? Many thanks with solution
list = [
{
"name": "Apple",
"id": 1,
},
{
"name": "Orange",
"id": 2,
}
]
watch: {
food: function (val) {
//Get food name by val(id)
}
}
Use Array.find method, which returns the value of the first element in the array that satisfies the provided testing function:
var food = list.find(food => food.id === val)
var name = food ? null : food.name
let list = [
{
"name": "Apple",
"id": 1,
},
{
"name": "Orange",
"id": 2,
}
]
console.log(
list.find(food => food.id === 1).name
)

Dynamic object key to display *ngFor in Nativescript with Angular

I have the dataset which has derived from the group by product name as below. I need to iterate the array of object and display the product name with all the size of the product.
Sample dataset
[ {
"TEST 1": [
{
"content_id": "88282",
"product_name": "TEST 1",
"price": "36.00",
"size" : "XL"
},
{
"content_id": "88283",
"product_name": "TEST 1",
"price": "37.00",
"size" : "XXL"
}
}],
{
"TEST 2": [
{
"content_id": "882821",
"product_name": "TEST 2",
"price": "36.00",
"size" : "XL"
},
{
"content_id": "882832",
"product_name": "TEST 2",
"price": "37.00",
"size" : "XXL"
}]
]
I need to iterate the above result and need to display as Product name with all sizes such as "TEST 1 (XL XXL ) and TEST 2 (XL XXL)
What I am trying is
<----- need to display here --------->
You can use Object.keys() to get keys or use foreach() to iterate json.
E.g.
const object1 = {"data":
[ { "TEST 1": [ {
"content_id": "88282",
"product_name": "TEST 1",
"price": "36.00",
"size" : "XL"
}, {
"content_id": "88283",
"product_name": "TEST 1",
"price": "37.00",
"size" : "XXL"
}
]
}
]
};
object1[Object.keys(object1)[0]].forEach(function(element) {
console.log(element);
});

Use object instead of array in datatables

When using datatables, I get 'no data available in table' when using an object instead of array:
var data1 =
{
"status": "success",
"districts": {
"1": {
"district_number": "1",
"district_name": "district one"
},
"2": {
"district_number": "2",
"district_name": "district two"
}
},
"time": "1.109s"
};
var table1 = jQuery("#data_table1").DataTable({
"data": data1.districts,
"aoColumns": [
{ "mData": "district_number" },
{ "mData": "district_name" }
]
});
I can get an array to display in a datatable using mData as follows:
var data2 =
{
"status": "success",
"districts": [
{
"district_number": "1",
"district_name": "district one"
},
{
"district_number": "2",
"district_name": "district two"
}
],
"time": "1.109s"
};
var table2 = jQuery("#data_table2").DataTable({
"data": data2.districts,
"aoColumns": [
{ "mData": "district_number" },
{ "mData": "district_name" }
]
});
https://jsfiddle.net/w93gubLv/
Is there a way to get datatables to utilize the object in the original format, or must I convert the object to an array?
You can write your own function to convert one format to another, for example:
function formatData(data){
var result = [];
for(prop in data){
if(data.hasOwnProperty(prop)){
result.push( data[prop] );
}
}
return result;
}
You can then later use it to pass data to jQuery DataTables as shown below.
var table1 = jQuery("#data_table1").DataTable({
"data": formatData(data1.districts),
"aoColumns": [
{ "mData": "district_number" },
{ "mData": "district_name" }
]
});
See updated jsFiddle for code and demonstration.

Transform JSON response with lodash

I'm new in lodash (v3.10.1), and having a hard time understanding.
Hope someone can help.
I have an input something like this:
{
{"id":1,"name":"Matthew","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":2,"name":"Mark","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":3,"name":"Luke","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":4,"name":"John","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":5,"name":"Paul","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}}
];
I would like to output this or close to this:
{
"industries": [
{
"industry":{
"id":5,
"name":"Medical",
"companies": [
{
"company":{
"id":1,
"name":"abc",
"employees": [
{"id":1,"name":"Matthew"},
{"id":2,"name":"Mark"},
{"id":3,"name":"Luke"},
{"id":4,"name":"John"},
{"id":5,"name":"Paul"}
]
}
}
]
}
}
]
}
Here's something that gets you close to what you want. I structured the output to be an object instead of an array. You don't need the industries or industry properties in your example output. The output structure looks like this:
{
"industry name": {
"id": "id of industry",
"companies": [
{
"company name": "name of company",
"id": "id of company",
"employees": [
{
"id": "id of company",
"name": "name of employee"
}
]
}
]
}
}
I use the _.chain function to wrap the collection with a lodash wrapper object. This enables me to explicitly chain lodash functions.
From there, I use the _.groupBy function to group elements of the collection by their industry name. Since I'm chaining, I don't have to pass in the array again to the function. It's implicitly passed via the lodash wrapper. The second argument of the _.groupBy is the path to the value I want to group elements by. In this case, it's the path to the industry name: company.industry.name. _.groupBy returns an object with each employee grouped by their industry (industries are keys for this object).
I then do use _.transform to transform each industry object. _.transform is essentially _.reduce except that the results returned from the _.transform function is always an object.
The function passed to the _.transform function gets executed against each key/value pair in the object. In the function, I use _.groupBy again to group employees by company. Based off the results of _.groupBy, I map the values to the final structure I want for each employee object.
I then call the _.value function because I want to unwrap the output collection from the lodash wrapper object.
I hope this made sense. If it doesn't, I highly recommend reading Lo-Dash Essentials. After reading the book, I finally got why lodash is so useful.
"use strict";
var _ = require('lodash');
var emps = [
{ "id": 1, "name": "Matthew", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 2, "name": "Mark", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 3, "name": "Luke", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 4, "name": "John", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 5, "name": "Paul", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } }
];
var result = _.chain(emps)
.groupBy("company.industry.name")
.transform(function(result, employees, industry) {
result[industry] = {};
result[industry].id = _.get(employees[0], "company.industry.id");
result[ industry ][ 'companies' ] = _.map(_.groupBy(employees, "company.name"), function( employees, company ) {
return {
company: company,
id: _.get(employees[ 0 ], 'company.id'),
employees: _.map(employees, _.partialRight(_.pick, [ 'id', 'name' ]))
};
});
return result;
})
.value();
Results from your example are as follows:
{
"Medical": {
"id": 5,
"companies": [
{
"company": "abc",
"id": 1,
"employees": [
{
"id": 1,
"name": "Matthew"
},
{
"id": 2,
"name": "Mark"
},
{
"id": 3,
"name": "Luke"
},
{
"id": 4,
"name": "John"
},
{
"id": 5,
"name": "Paul"
}
]
}
]
}
}
If you ever wanted the exact same structure as in the questions, I solved it using the jsonata library:
(
/* lets flatten it out for ease of accessing the properties*/
$step1 := $ ~> | $ |
{
"employee_id": id,
"employee_name": name,
"company_id": company.id,
"company_name": company.name,
"industry_id": company.industry.id,
"industry_name": company.industry.name
},
["company", "id", "name"] |;
/* now the magic begins*/
$step2 := {
"industries":
[($step1{
"industry" & $string(industry_id): ${
"id": $distinct(industry_id)#$I,
"name": $distinct(industry_name),
"companies": [({
"company" & $string(company_id): {
"id": $distinct(company_id),
"name": $distinct(company_name),
"employees": [$.{
"id": $distinct(employee_id),
"name": $distinct(employee_name)
}]
}
} ~> $each(function($v){ {"company": $v} }))]
}
} ~> $each(function($v){ {"industry": $v} }))]
};
)
You can see it in action on the live demo site: https://try.jsonata.org/VvW4uTRz_