Querying JSON array in JSON object value - javascript

Using jsonSelect Plugin I am trying to do a query select as below. I am presenting this example.
How can I retrieve the All Project and Contractors who has the Projects in "North" ProjectArea? I already tried this to get the contractor's name but it didn't work
var contractors = [{
"contractor1": [{
"project": "Project 2",
"projectArea": "South"
},
{
"project": "Project 101",
"projectArea": "East"
}],
"contractor2": [{
"project": "Project 500",
"projectArea": "North"
},
{
"project": "Projetc 108",
"projectArea": "West"
}]
}]
var stringSelect = 'has(:root > .projectArea:val("North"))';
JSONSelect.forEach(stringSelect, contractors, function (resultObj) {
$('body').append('<p>' + resultObj + '</p>');
});

I think the only way you are going to be able to achieve what you want is by changing your JSON data structure. Specifically, you have your contractors' names as keys ('contractor1', contractor2'), but they really should be values. The library you are using returns a set of objects, but I don't see any way to step back a level and obtain each object's corresponding key. I suggest structuring your data like this:
var contractors = [
{
"name": "contractor1",
"projects": [
{ "project": "Project 2", "projectArea": "South" },
{ "project": "Project 101", "projectArea": "North" }
]
},
{
"name": "contractor2",
"projects": [
{ "project": "Project 500", "projectArea": "North" },
{ "project": "Project 108", "projectArea": "West" }
]
}
];
Also, I think you will have to apply two levels of filters, first to get the contractors, and secondly to get each contractor's projects:
JSONSelect.forEach('object:has(.projects:has(.projectArea:val("North")))', contractors, function (contractor) {
$('body').append('<p>' + contractor.name + '</p>');
JSONSelect.forEach('object:has(.projectArea:val("North"))', contractor.projects, function (project) {
$('body').append('<p>' + project.project + '</p>');
});
});
I do not know of any other plugins that do this. If I were to come across this problem, my first inclination would be to solve it using jQuery's $.map and $.grep methods:
var filtered = $.map(contractors, function (contractor) {
var filteredProjects = $.grep(contractor.projects, function (project) {
return project['projectArea'] === 'North';
});
if (filteredProjects.length) {
return {
'name': contractor.name,
'projects': filteredProjects
};
}
});
I am using $.grep to filter each contractor's projects to only those with ['projectArea'] === 'North'. If the contractor has any projects that match the filter, a new object with the contractor's name and the filtered projects gets added to my filtered var.

Related

JS - copy object from an array to the new one when the condition is met [edited]

What I have to do is filter the array and write selected elements in the new one. Previously I saw two possible ways, but thanks to comments bellow I realised that way with deleting elements from array is not good. So what I need to do is to copy some elements (i.e. everything with category "science") to new one. My first question is: which approach is better? more efficient? Thank you for your help!
Now second question. How can I copy elements from my array to the new one? It was not a problem to copy only a book name form element with id 0. But when I was trying to copy id, name, category, price and image is exactly the same form to the new array the attempt failed...
My array is:
var products =
[
{
"id": "0",
"name": "Book Name",
"category": "science",
"price": "$49,99",
"image": "img/product-1.png"
},
{
"id": "1",
"name": "Book Name 2",
"category": "computers",
"price": "$319",
"image": "img/product-2.png"
},
{
"id": "2",
"name": "Book Name 3",
"category": ["science", "programming", "computers"],
"price": "$49,99",
"image": "img/product-1.png"
}
]
below I tried to remove mismatched elements, but this approach turned out to be less effective and more problematic.
let checkedOperations = 'programming';
let selected_products = [... products];
$(document).ready(function () {
for (var i in products) {
if (isTrue(checkedOperations, products[i].category)) {
selected_products.splice(i,1);
}
console.log('selected products after slice -1 = ' + selected_products[1].name);
console.log('selected products after slice = ' + selected_products[2].name);
console.log('selected products after slice +1 = ' + selected_products[3].name);
}
});
Using forEach should do the trick without handling indexes and thus making it less error-prone.
let resArray = []; // Filtered result array
products.forEach((el) => {
if (el.id === "0") { // Whatever condition you want
resArray.push(el);
}
})

How to delete nested json key dynamically?

This is the sample json:
{
"search": {
"facets": {
"author": [
],
"language": [
{
"value": "nep",
"count": 3
},
{
"value": "urd",
"count": 1
}
],
"source": [
{
"value": "West Bengal State Council of Vocational Education & Training",
"count": 175
}
],
"type": [
{
"value": "text",
"count": 175
}
],
}
}
There are several ways to delete key search.facets.source:
delete search.facets.source
delete jsobObj['search']['facets']['source']
var jsonKey = 'source';
JSON.parse(angular.toJson(jsonObj), function (key, value) {
if (key != jsonKey)
return value;
});
Above 1 & 2 are not dynamic, and 3 is one of the way but not a proper way. Because if source is present in another node then it will not work. Please anybody can tell me how to delete it dynamically in any kind of nested key. Because we can not generate sequence of array dynamically in above 2.
Assuming you're starting from this:
let path = 'search.facets.source';
Then the logic is simple: find the search.facets object, then delete obj['source'] on it.
Step one, divide the path into the initial path and trailing property name:
let keys = path.split('.');
let prop = keys.pop();
Find the facets object in your object:
let parent = keys.reduce((obj, key) => obj[key], jsonObj);
Delete the property:
delete parent[prop];
I have found out another solution, it is very easy.
var jsonKey = 'search.facets.source';
eval('delete jsonObj.' + jsonKey + ';');

Push Json filtered key values to nested ul with Javascript

I need help pushing the values from a filtered json, I need this generate a nested ul list, I can not modify the json format at this point, I you check the console.log you will see the values to create the list, at this point I can't figure how to complete the 'for loop' to render the html markup needed, any help will be appreciated, this is the jsfiddle http://jsfiddle.net/43jh9hzz/, and if you check the console log you will see the values.
This is the Js:
var json='';
var property_set = new Set();
function iterate(obj, stack) {
json="<ul>";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
}
else {
// console.log(property);
property_set.add(property);
json+="<li>";
if(typeof obj[property] !== "number") {
json+="<li>"+obj[property]+"</li>";
console.log(obj[property]);
}
}
} json += "</li>";
}
}
var listEl = document.getElementById('output');
iterate(jsonObj)
And this is the json format:
var jsonObj =
{
"level_1": [
{
"level_1_name": "CiscoSingaporeEBC",
"level_2": [
{
"level_2_name": "Khoo Tech Puat",
"level_2_id": 2222,
"level_3": [
{
"name": "Boon Leong Ong",
"id": 6919
},
{
"name": "Kiat Ho",
"id": 6917
},
{
"name": "Overall Experience",
"id": 6918
}
]
}
]
},
{
"level_1_name": "CiscoLondonEBC",
"level_2": [
{
"level_2_name": "Bernard Mathews Ltd.",
"level_2_id": 2367,
"level_3": [
{
"name": "Barry Pascolutti",
"id": 7193
},
{
"name": "Kathrine Eilersten",
"id": 7194
},
{
"name": "Martin Rowley",
"id": 7189
}
]
},
{
"level_2_name": "FNHW Day 1",
"level_2_id": 5678,
"level_3": [
{
"name": "Jurgen Gosch",
"id": 7834
},
{
"name": "Overall Experience",
"id": 7835
}
]
},
{
"level_2_name": "Groupe Steria Day 1",
"level_2_id": 2789,
"level_3": [
{
"name": "Adam Philpott",
"id": 7919
},
{
"name": "Pranav Kumar",
"id": 7921
},
{
"name": "Steve Simlo",
"id": 7928
}
]
}
]
}
]
};
enter code here
I'm not sure if I am interpretting your request correctly, but I think this is what you want: http://jsfiddle.net/mooreinteractive/43jh9hzz/1/
Basically, you are calling the iterate function to run, but then that's it. The function actually needs to also return the value it generates.
I've added to the end of the function, after the for loop completes:
return json;
Do now the function returns the value it generated, but there are some other issues too. When you recursively call the iterate function again inside the iterate function, you actually want to add what it returns to the current json string housing all of your returned value.
So on that line I changed it from:
iterate(obj[property], stack + '.' + property);
to
json += iterate(obj[property], stack + '.' + property);
Now that other value will come back as well inside the main list you were creating in the first run of the function. Ok so that's pretty close, but one more small thing. I think when you added additional surrounding LI, you actually wanted to do an UL. I changed those to ULs and now I think the result is like a UL/LI list representing the text parts of the JSON object.
Again, that may not be exactly what you were after, but I think the main take away is using the function to return the value, not just generate it, then do nothing with it.

How to parse a JSON array string in JavaScript?

I have an JSON array like this
var filter_value_data = [{"Status":[{"name":"Open","id":"1"},{"name":"Pending","id":"2"},{"name":"Resolved","id":"3"},{"name":"Closed","id":"4"},{"name":"Evaluation","id":"5"}]},{"Payment Status":[{"name":"Paid","id":"10"},{"name":"UnPaid","id":"11"},{"name":"Part Paid","id":"12"}]},{"Priority":[{"name":"Low","id":"6"},{"name":"Medium","id":"7"},{"name":"High","id":"8"},{"name":"Urgent","id":"9"}]}]
I have tried filter_value_data["Status"] which is obviously wrong. How do I get the JSON elements for Status using the names like Status,Payment Status?
filter_value_data is an array (having []), so use filter_value_data[0].Status to get the first element-object with property "Status".
It is always good to format your code in order to see the hierarchy of the structures:
var filter_value_data = [
{
"Status": [
{
"name": "Open",
"id": "1"
}, {
"name": "Pending",
"id": "2"
}, ...
]
}, {
"Payment Status": [
{
"name": "Paid",
"id": "10"
}, ...
]
}, {
"Priority": [
{
"name": "Low",
"id": "6"
}, ...
]
}
];
With your current JSON you can't get the elements with the name alone.
You can get Status with filter_value_data[0]['Status'] and Payment status with filter_value_data[1]['Payment Status'].
This is because the keys are in seperate objects in the array.
In order to get them with filter_value_data['Status'] you need to change your JSON to
var filter_value_data = {
"Status":[
{"name":"Open","id":"1"},
{"name":"Pending","id":"2"},
{"name":"Resolved","id":"3"},
{"name":"Closed","id":"4"},
{"name":"Evaluation","id":"5"}
],
"Payment Status":[
{"name":"Paid","id":"10"},
{"name":"UnPaid","id":"11"},
{"name":"Part Paid","id":"12"}
],
"Priority":[
{"name":"Low","id":"6"},
{"name":"Medium","id":"7"},
{"name":"High","id":"8"},
{"name":"Urgent","id":"9"}
]
};
I wrote this on my phone so it's not as well-formatted as usual. I'll change it ASAP.
With your current JSON, created a result which might be helpful for you.
JS:
$.each(filter_value_data,function(ind,val){
var sta = val.Status; // Status Object get displayed
for(var i=0;i<sta.length;i++){
var idVal= sta[i].id;
var nameVal = sta[i].name;
Statusarray.push(idVal,nameVal);
console.log(Statusarray);
}
})
FiddleDemo
You can use below code, it will return status object
filter_value_data[0]['Status']
filter_value_data[0]['Payment Status']
to get Single value you use :
filter_value_data[0]['Status'][0]['name']

Knockout.js updating array within an array

I have an array in Knockout view model which looks like so:
this.Activities = ko.observableArray([
{ "date": "28/11/2012 00:00:00",
"activities": [
{ "company": "BOW",
"description": "Backup Checks",
"length": "60"
},
{ "company": "AMS",
"description": "Data Request",
"length": "135"
},
]},
{ "date": "30/11/2012 00:00:00",
"activities": [
{ "company": "BOW",
"description": "Backup Checks",
"length": "60"
},
{ "company": "SLGT",
"description": "Software Development",
"length": "240"
},
{ "company": "BOW",
"description": "Data Request",
"length": "30"
},
]},
]);
I use this code to add a new element to it:
this.Activities.push(new NewActivity(company, description, length, fullDate));
Which uses NewActivity function:
function NewActivity(company, description, length, date) {
this.date = date;
this.activities = [{ "company": company, "description": description, "length": length }];
}
And it works fine. However, it creates an entirely new object every time it is getting released. I need to implement a condition when the code would check for the date of the objects already created. If the newly created object had the same date, activity details should be added to activities array within the Activities array for that date.
How can I do it?
All of the data for the Activities array comes from the model in the strongly typed view in MVC application:
this.Activities = ko.observableArray([
#foreach (ActivitySet aSet in Model)
{
#:{ "date": "#aSet.Date",
#:"activities": [
foreach(Activity a in aSet.Activities)
{
#:{ "company": "#a.Companies.Select(c => c.Title).Single()",
#:"description": "#a.Descriptions.Select(c => c.Title).Single()",
#:"length": "#a.LengthInMinutes"
#:},
}
#:]},
}
]);
I suggest that you create a few entities describing your activities:
// Details
function ActivityDetails(company, description, length) {
this.company = ko.observable(company);
this.description = ko.observable(description);
this.length = ko.observable(length);
}
// Activity
function Activity(date, activityDetails) {
this.date = ko.observable(date);
this.details = ko.observableArray(activityDetails);
}
The you can control activities in the following manner:
function ViewModel () {
var self = this;
this.Activities = ko.observableArray([
// Activities here
]);
this.addActivity = function (activity) {
var flag = false;
ko.utils.arrayMap(self.Activities(), function (item) {
// Flag is here so it doesn't keep checking further in iterations
if (!flag) {
if (item.date() === activity.date()) {
item.details.push(activity.details);
flag = true;
}
}
});
// Case where activity date was not found in existing records
if (!flag) {
self.Activities.push(activity);
}
}
}
This requires your view model to have a custom add method which I have provided an example of. Note that everywhere I am resolving observable values, so if you are using non-observable ones remove the function calls.

Categories