Finding matching keys in array/json jquery - javascript

Using $.getJSON to get data from external .json file with following content.
{
data:[
{
"1apps":"1",
"abc" "xyz"
},
{
"apps":"2",
"abc" "xyz"
},
{
"2apps":"3",
"abc" "xyz"
}
]
}
I want to find the data which keys matching apps. In this case, 1apps, apps, 2apps will be the output.

You can use filter and then iterate on obj , then use a include function determines whether a string contains the characters of a specified string
var obj = {
data: [{
"1apps": "1",
"abc": "xyz"
},
{
"apps": "2",
"abc": "xyz"
},
{
"2apps": "3",
"abc": "xyz"
}
]
};
var list = obj["data"];
var matchedKeys = [];
list.filter(function(k, v) {
for (var i in k) {
if (i.includes('apps')) {
matchedKeys.push(i);
return k;
}
}
});
console.log(list)
console.log(matchedKeys);

You can simply use reduce and filter to get the keys that include apps
const obj = {
data:[
{
"1apps":"1",
"abc" :"xyz"
},
{
"apps":"2",
"abc" :"xyz"
},
{
"2apps":"3",
"abc" :"xyz"
}
]
}
const res = obj.data.reduce((a,b) => a.concat(...Object.keys(b).filter(x => /apps/.test(x))), []);
console.log(res);

Related

How to read the dynamic objects data present in JSON?

I am obtaining a JSON from another application. I would like to parse that JSON and read the data present in them. The JSON contains some of the user-defined data which are dynamic and the key/value pair can be dynamic so I am a bit confused about how to read these dynamic data and do further processing.
Following is the sample JSON that I would like to process:
{
"context": [
{
"one": "https://example.one.com"
},
{
"two": "https://example.two.com"
},
{
"three": "https://example.three.com"
}
],
"name": "Batman",
"age": "30",
"one:myField": {
"two:myField2": "Hello"
},
"three:myField3": "Hello2"
}
I am able to read some of the static/well-defined data directly such as name & age but I am not understanding how to read some of the user-defined/dynamic data from this JSON as it does not have a definite key/value or there is no guarantee that it will appear in the order after the age property.
I am trying to find a way to read/obtain all the user-defined data from this JSON:
"one:myField": {
"two:myField2": "Hello"
},
"three:myField3": "Hello2"
Is there a direct way to achieve this or use some library? I am developing the application using Vuejs/Nuxtjs.
I think that's not the best api you are using, you should have constant object parameters that you always know how to find things. If you want to find not known parameters you can parse JSON to object and loop throug it.
const object = { a: 1, b: 2, c: 3 };
for (const property in object) {
console.log(`${property}: ${object[property]}`);
}
You can simply achieve that by iterating over Object.keys().
Demo :
const jsonData = {
"context": [
{
"one": "https://example.one.com"
},
{
"two": "https://example.two.com"
},
{
"three": "https://example.three.com"
}
],
"name": "Batman",
"age": "30",
"one:myField": {
"two:myField2": "Hello"
},
"three:myField3": "Hello2"
};
Object.keys(jsonData).forEach(key => {
if (typeof jsonData[key] === 'object') {
Object.keys(jsonData[key]).forEach(innerObjKey => {
console.log(innerObjKey, jsonData[key][innerObjKey])
})
} else {
console.log(key, jsonData[key])
}
})
Combining Object.keys with a recursive function, even if you have multiple nested objects, it will work without having to refactor your code everytime!
const jsonData = {
context: [
{
one: "https://example.one.com",
},
{
two: "https://example.two.com",
},
{
three: "https://example.three.com",
},
],
name: "Batman",
age: "30",
"one:myField": {
"two:myField2": "Hello",
"one_nested:myField": {
another_nested_key: "another_nested_value",
},
},
"three:myField3": "Hello2",
};
recursive(jsonData);
function recursive(nestedKey) {
if (typeof nestedKey !== "object") return;
Object.keys(nestedKey).forEach((key) => {
if (typeof nestedKey[key] === "object") {
recursive(nestedKey[key]);
} else {
console.log(key, nestedKey[key]);
// add your conditions here
if (key === "name") {
// bla bla bla
}
}
});
}

Merge two json arrays

I have to array i want to merge them in one array by same id. So every two array have same id should be merged
Case 1:
{
"id":1212,
"instructor":"william",
...
}
Case 2:
[
{
"id":1212,
"name":"accounting",
...
},
{
"id":1212,
"name":"finance",
...
}
]
I need the result to be :
{
"id": 1212,
"instructor": "william",
"Courses": [
{
"id":1212,
"name":"accounting",
...
},
{
"id":1212,
"name":"finance",
...
}
]
}
What you're asking isn't merging, but here is how you can do that.
const instructors = [{ "id":1212, "instructor":"william", }];
const courses = [
{ "id":1212, "name":"accounting" },
{ "id":1212, "name":"finance" }
];
const expected = [{ "id":1212, "instructor":"william", "courses": [
{ "id":1212, "name":"accounting" },
{ "id":1212, "name":"finance" }
]}];
const composed = instructors.map(ins => {
const ret = {...ins};
ret.courses = courses.filter(cou => cou.id === ins.id);
return ret;
});
console.log(composed);
var finArr;
var course = [];
use forEach loop javascript get all value in put your value instead of varid and varname
course.push({"id":varid,"name":varname});
finArr = {"id":variableId,"instructor":variablename,"Courses":course}

Create JSON Array dynamically from an object

I have an object A as shown below.
var A = {
"1": [ "1_1", "1_2", "1_3" ],
"2": [ "2_1", "2_2" ]
};
Need to build a new array dynamically using js. Suppose
object A key should map to attribute text of Array AA and value should be to children as given below.
var AA = [
{
"text": "1",
"state": "open",
"children": [
{ "text": "1_1" },
{ "text": "1_2" },
{ "text": "1_3" }
]
},
{
"text": "2",
"state": "open",
"children": [
{ "text": "2_1" },
{ "text": "2_2" }
]
}
];
This is my function but its not working as expected. Could someone pls help?
function constructJSONArr() {
var A = {
"1": [ "1_1", "1_2", "1_3" ],
"2": [ "2_1", "2_2" ]
};
for (var key in A) {
var tempArr = [];
tempArr.push(key);
for (var i = 0; i < key.length; i++) {
return {
'text': key,
'state': 'closed',
'children': A[key].map(function(child) {
return {
'text': child
};
})
}
}
}
}
When you return inside a function, the function ends and returns immediately. In your case, the return inside the for loop causes the function to return the 1st key object. To solve this, you need to create the objects and push them into an arr. You can return freely inside Array.map() because each iteration invokes a function.
Fixed solution:
Iterate with for...in. Get the key. Push a new object into arr. Use the key as the text property, the state, and children. To create the children get the array from the original object by the key, and use Array.map() to generate the child objects. Return arr.
var A = {
"1": ["1_1", "1_2", "1_3"],
"2": ["2_1", "2_2"]
};
function constructJSONArr(A) {
var arr = [];
for (var key in A) {
arr.push({
text: key,
state: 'closed',
children: A[key].map(function(t) {
return {
text: t
};
})
});
}
return arr;
}
var result = constructJSONArr(A);
console.log(result);
ESNext solution
Use Object.entries() to get keys and respective values from the object A. Iterate the entries with two nested Array.map() calls. The 1st to create the outer object, and the 2nd to create the children.
const A = {
"1": ["1_1", "1_2", "1_3"],
"2": ["2_1", "2_2"]
};
const constructJSONArr = (obj) =>
Object.entries(obj).map(([text, children]) => ({
text,
state: 'closed',
children: children.map((text) => ({
text
}))
}));
var result = constructJSONArr(A);
console.log(result);
You can use Object.keys() to iterate through the object and Array.map to create the new array.
var A = {
"1": ["1_1", "1_2", "1_3"],
"2": ["2_1", "2_2"]
};
var transformed = Object.keys(A).map(key => {
return {
text: key,
state: "open",
children: A[key].map(value => {
return {
text: value
};
})
};
});
console.log(transformed);

Lowdb count each string in an array of objects

I'm trying to count the number of string in an array of objects using lowdb.
Here is a sample of my objects:
{
"tags": [
"test",
"test2"
]
},
{
"tags": [
"test",
"test3"
]
}
I'd like to get this:
{
test: 2,
test2: 1,
test3: 1
}
I have successfully get this doing like this:
_.each(selectAll().value(), (bookmark) => {
if (bookmark.tags.length > 0) {
_.each(bookmark.tags, (bookmarksTags) => {
if (!(bookmarksTags in tags)) {
tags[bookmarksTags] = 0
}
tags[bookmarksTags]++
})
}
})
It works but... it's ugly and I don't like it. Do you know a better and proper Lodash's way to do this?
You can use reduce() and forEach() with plain javascript.
var data = [{"tags":["test","test2"]},{"tags":["test","test3"]}]
var result = data.reduce(function(r, e) {
return (e.tags.forEach(e => r[e] = (r[e] || 0) + 1)), r
}, {})
console.log(result)
One way using Lodash:
_.countBy(_.flatMap(arr,'tags'))
Where arr is the source array
var o = [{ "tags": [ "test", "test2" ]},{ "tags": [ "test", "test3" ]}];
console.log(_.countBy(_.flatMap(o,'tags')));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

combine json array into one json array by id

I want to merge item and purchases array of json into one by matching their property value.
Here's the source :
{
"item": [
{
"invoiceId": 1
},
{
"invoiceId": 2
},
{
"invoiceId": 3
}
],
"purchase": [
{
"id": "1",
"date": "12/1/2014"
},
{
"id": "2",
"date": "12/1/2014"
},
{
"id": "3",
"date": "12/1/2014"
}
]
}
I want to produce something like this :
{
"combined": [
{
"invoiceId": 1,
"id": "1",
"date": "12/1/2014"
},
{
"invoiceId": 2,
"id": "2",
"date": "12/1/2014"
},
{
"invoiceId": 3,
"id": "3",
"date": "12/1/2014"
}
]
}
How can I match the item.invoiceId with purchase.id?
Solution
assuming obj is your object
var new_obj = {combined:[]};
obj["purchase"].forEach(function(a) {
obj["item"].forEach(function(b){
if (+b["invoiceId"]===(+a["id"])) {
a["invoiceId"] = b["invoiceId"] || 0;//WILL MAKE INVOICEID 0 IF IT IS NOT DEFINE. CHANGE 0 TO YOUR NEEDS
new_obj.combined.push(a);
}
});
});
How it works
The first .forEach() loops through obj.purchase. Then we loop through obj.item To check if their is a matching invoiceId (if you don't need to make sure their is a matching invoiceId, use the alternate code). Then, we simply add a new value to the new_obj
The result (copied from console) is:
{
"combined":[
{
"id":"1",
"date":"12/1/2014",
"invoiceId":1
},
{
"id":"2",
"date":"12/1/2014",
"invoiceId":2
},
{
"id":"3",
"date":"12/1/2014",
"invoiceId":3
}
]
}
Alternative Code
Use this if you don't need to make sure, invoiceId is there
var new_obj = {combined:[]};
obj["purchase"].forEach(function(a){a["invoiceId"]=a["id"];new_obj.combined.push(a);});
One way of achieving what you want will be
var result = {};
var getMatchingPurchase = function(invoiceId) {
return data.purchase.filter(function(purchase) {
return invoiceId == purchase.id;
})[0];
};
result.combined = data.item.map(function(invoice) {
var purchase = getMatchingPurchase(invoice.invoiceId);
return {
invoiceId: invoice.invoiceId,
id: purchase.id,
date: purchase.date
};
});
console.log(result);
It will print like bellow
{ combined:
[ { invoiceId: 1, id: '1', date: '12/1/2014' },
{ invoiceId: 2, id: '2', date: '12/1/2014' },
{ invoiceId: 3, id: '3', date: '12/1/2014' } ] }
Note:- I'm using map and filter functions which are not supported in IE8. If you want to use in IE8 you have to use for loop.
If you have to support old browsers like IE8 (poor guy...), note that the native forEach might not be supported, in this case you can use lodash for cross-browser compatibility:
function getCombinedResult(source){
var combinedList = [];
_.each(source.item, function(item){
_.each(source.purchase, function(purchase){
if (item['invoiceId'].toString() != purchase['id'].toString()) return;
var combinedItem = _.extend(item, purchase)
combinedList.push(combinedItem);
});
})
return {"combined": combinedList};
}

Categories