rebuild Json List - javascript

// Start with this JSON
var initialJson = {
"rows": [{
"ID": 123,
"Data": 430910,
"VersionNum": 0,
"RowSeqNum": 1,
"IterationNum": 1,
"FirstName": "Aqwemara",
"LastName": "Seweqweebi",
"Location": "CweAN",
"Role": "Site",
"In_Out": "Internal",
"Editor": "User1",
"Edit_Date": "2015%2D02%2D25T15%3A30%3A47%2E883Z"
}]
};
//Create an array that lists the Keys for the NEW JSON
var hResponse = [];
hResponse.push("FirstName", "LastName", "Location", "Role", "Editor", "Edit_Date");
var wbuResponse = [];
// When GO! button is pressed, process the "initialJson" object, creating a new object with only the Keys listed in "hResponse" array
$(document).ready(function() {
$('.btn').click(function() {
wbuResponse.push(
for each(hHeading in hResponse[{
hHeading: response[i].hHeading
}]);
console.log(JSON.stringify(wbuResponse));
});
});
//console setup
var consoleLine = "<p class=\"console-line\"></p>";
console = {
log: function(text) {
$("#console-log").append($(consoleLine).html(text));
}
};
.console-line {
font-family: console;
margin: 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input class="btn" type="button" id="btn" value="Go!">
<div id="console-log"></div>
I want to take the initialJson , I will modify the pairs, then rebuild the JSON based on the entries in the hResponse array.
Focusing on the rebuild part, I only want to take a certain amount of the keys and put them into the new JSON array.
Can i do a for each loop within the wbuResponse.push to create the correct structure?
Am I doing this right, maybe there is a better more efficient way?
Thanks
JSFIDDLE : https://jsfiddle.net/b5m0nk67/5/

What you're looking for is called map. It's a built-in function in modern JavaScript implementations: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Using .map(), your filtering code could look something like this:
var wbuResponse = initalJson.map(function(row, index) {
return {
FirstName: row.FirstName,
LastName: row.LastName,
Location: row.Location,
Role: row.Role,
Editor: row.Editor,
Edit_Date: row.Edit_Date
};
});
If you wanted to use an approach like the one you're alluding to, with an array of property names to filter down to rather than having it hard-coded, you could do something like this:
var props = ["FirstName", "LastName", "Location", "Role", "Editor", "Edit_Date"];
var wbuResponse = initalJson.map(function(row, index) {
var mappedRow = { };
for (var i = 0; i < props.length; i++) {
mappedRow[props[i]] = row[props[i]];
}
return mappedRow;
});
For broader browser support, you can use jQuery's built-in map function that includes a polyfill for browsers that don't support it natively. A few examples of that here: http://encosia.com/use-jquery-to-extract-data-from-html-lists-and-tables/

Related

Embedded Objects to Arrays

I was given an existing project where the data structure is below:
[
{
"key": "username",
"value": ""
},
{
"key": "password",
"value": ""
},
{
"key": "cars",
"value": [
{"ABC-1234-1234": "s4LmoNzee9Xr6f7uu/"},
{"ABC-5678-5678": "s5LmoNzee9Xr5f9uu/"}
]
}
]
Cars' value is an array of objects.
To create the initial object in the cars' array, I do the following:
var encryptedStuff = json.data;
var carkey = carid;
var entry = {};
entry[carkey] = encryptedStuff;
var carArray = [];
key="cars";
carArray.push(entry);
I need to push the array into another function that turns it into a string in a stored variable.
My problem...and I'm really rusty on embedded objects...is to do the following:
1.) Get the string
2.) JSON.parse back into an object (I got this far as I'm using a jQuery grep but I'd prefer to use JavaScript).
Here's my problem...
3.) locate the cars key in the object and get its value.
4.) Turn the value into an array to either delete an item or to add one (as per the code above where I'm writing the object into the array.
In the case of adding, I would have to copy the cars' value into the carArray[] and then push the new item into it.
In the case of deleting, I would have to remove the item and push back everything back into the carArray[].
I would do things differently but I can't change the structure of the data as this is approved company-wide.
Any help would be appreciated.
Thanks
You don't need to make a copy of the car's value array to add new entries nor make a copy then "push back" to remove an entry - you can reference it directly in the parsed object.
You can use
JSON.parse
array.find
array.push
array.splice
JSON.stringify
Giving:
var source = `[
{
"key": "username",
"value": ""
},
{
"key": "password",
"value": ""
},
{
"key": "cars",
"value": [
{"ABC-1234-1234": "s4LmoNzee9Xr6f7uu/"},
{"ABC-5678-5678": "s5LmoNzee9Xr5f9uu/"}
]
}
]`
// convert json to an object
var data = JSON.parse(source);
console.log(data, data.find(e=>e.key=="cars").value)
// add an item to the cars.value
data.find(e=>e.key=="cars").value.push({"ABC-": "s6..." });
// remove an item from the cars.value
data.find(e=>e.key=="cars").value.splice(1,1);
// confirm items added/removed
console.log(data, data.find(e=>e.key=="cars").value)
// convert back to a strng to send back to the service
var result = JSON.stringify(data);
console.log(result);

Adding a new object into a nested array

I want to add a new object for each nested array. I'm calling this function any time I add a product to my orderintake:
add2order(productID, productName, productRatePlans) {
this.orderIntake.push({ productID, productName, productRatePlans });
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
this is an example response from the server:
{
"id": "8adc8f996928b9a4016929c59b943a8f",
"sku": "SKU-00006778",
"Partner_Account_ID__c": null,
"productRatePlans": [
{
"id": "8adce4216928c28d016929c59bff3372",
"status": "Active",
"name": "Enterprise",
"description": null,
"effectiveStartDate": "2016-02-26",
"effectiveEndDate": "2029-02-26",
"productRatePlanCharges": [
{
"id": "8adc8f996928b9a4016929c59d183a92",
"name": "USAGE_COUNTER_2",
"type": "Usage",
"model": "Volume",
"uom": "Each",
"pricingSummary": [
"Up to 5000 Each: USD0 flat fee"
],
"pricing": [
{
...
}
],
"defaultQuantity": null,
"applyDiscountTo": null,
"discountLevel": null,
"discountClass": null,
...
"financeInformation": {
..,
}
}
]
}
],
"productFeatures": [
{
...
}
]
}
The data is being retrived this way from an external REST backend so unfortunately I can't initialize the data including the new property...
so in every productRatePlanCharges there should be 1 new object 'quantity'.
How can I add this field to every productRatePlanCharges?
Right now I'm getting: ERROR
TypeError: Cannot read property 'productRatePlanCharges' of undefined
And how can I make sure I'm always adding this to the last orderIntake element? Don't mind productRatePlans there is only 1 in each orderintake...
thanks for your support!
Here you have to create productDetails object with inititalised array like below so that you won't get the error.
add2order(productID, productName, productRatePlans) {
// Create object like below
let productDetails = { productID : productID, productName : productName, productRatePlans : productRatePlans
}
this.orderIntake.push(productDetails);
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
Hope this will help!
as you used Angular you probably use Typescript too. I recommend that you create a model like your incoming model and there define your quantity: number inside productRatePlanCharges object. then map the incoming data to your own model. therefore you will have a quantity=0 in your model that you can change it later in a loop.
If you want to continue with your own way take a look at this:
Add new attribute (element) to JSON object using JavaScript
there is no problem to add an element to current model almost like you did, and the problem might be somewhere else as your error refers to existence of productRatePlanCharges!
as you used forEach I prefer to use that 'element' and double iterating with i++; is not a good idea to me.
this might be better:
element.quantity = element.defaultQuantity;

Angular ng-model & filter using nested data vs top layer

I have a list of data displayed on my page that is broken down into divs. Each div represents an array of data in my object, pretty common.
I am trying to add a text box to my page where I can filter out the data and it will narrow down the results shown on the page as more data is entered into the text box.
For that, I added a filter on my ngFor like so: *ngFor="let x of data | filter: filterString".
My text-box then uses ngModel to filter that data down:
<input type="text" class="form-control" placeholder="Filter..." name="ruleFilter" id="ruleFilter" [(ngModel)]="filterString" (keyup)="onFilter($event)">
The issue I am having is that the filter seems to only be working with the top layer of data in my object. For example, the data below is what one of the results looks like in my ngFor loop. I can search Omaha just fine since its in the top level and it filters it down correctly.
However, If I look for something like Campus which is nested inside Attribute, it doesn't find it in the filter and no results are shown.
{
"RuleParentID": "618",
"RuleVersionID": "18",
"MappedValue": "1",
"ProcessingOrder": 1,
"KeyID": "1",
"Value": "Omaha",
"IsRuleRetired": "0",
"UserImpactCount": "0",
"Attribute": [
{
"AttributeID": "6",
"AttributeName": "Campus",
"Operator": {
"OperatorID": "3",
"OperatorName": "In List",
"SqlOperator": "IN"
},
"AttributeValue": [
{
"AttrValue": "1",
"Value": "Omaha",
"IsValueRetired": "0",
"disabled": "False"
}
]
},
{
"AttributeID": "14",
"AttributeName": "Grade",
"Operator": {
"OperatorID": "1",
"OperatorName": "Greater Than",
"SqlOperator": ">"
},
"AttributeValue": [
{
"AttrValue": "14",
"Value": "14",
"IsValueRetired": "0",
"disabled": "False"
}
]
}
]
}
Is there any way to have the model look at all layers of the object for my binding instead of just the top layer (which I only assume its doing at this time) ?
Update: Here is a plunker of what my basic setup is like: https://plnkr.co/edit/eywuWmPRseUkmVPbTEOf?p=preview
You will see the data model that searches by the top level properties just fine, but when I search for something nested, I don't get any results back.
If I understand well the question, I think that to flat the data will help you:
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
};
let newData = flattenObject(data);
Code source: https://gist.github.com/penguinboy/762197
To achieve expected result , use below option
1.In your component below variable
jsonVal:any=JSON; // for using JSON.stringify and indexOf
Use *ngIf to filter value from input with indexOf
<input type="text" [(ngModel)]="filterString">
<div *ngFor="let data of result">
<div *ngIf="jsonVal.stringify(data).indexOf(filterString)!= -1">{{data| json}}</div>
</div>
code sample for reference - https://stackblitz.com/edit/angular-ht2afv?file=app/app.component.html
Just for testing , I have added another Object with Campus2 and Omaha2
When filtering on a nested property of data you can use the map function or similar.
This will be in your component and not the template. Filtering using pipes in the template is discouraged by the Angular team for performance reasons.
Instead I would do something like this:
const data = [{//your data}]
let filteredData = [];
data.map(val => {
if (val.Attribute.filter(name => name.AttributeName === "Foo").length > 0) {
filteredData.push(val)
}
});
I am assuming your data is an array of objects.
Beware I am mutating my data object. To avoid this you do this:
const data = [{//your original data}]
const dataToFilter = JSON.Parse(JSON.stringify(data))
This will make copy of your data without references to your original object. Useful if you want to clear your filter. Not useful if your data object contains functions.
On re-reading your question I think this is not the solution you were looking for but rather a method to look anywhere in the data. For this you should probably flatten your data as suggested by Zelda7. Another approach would be to extend a filtering method to explicitly filter on all relevant fields.

Update object with given ID embed in array without restructuring Mongo database

I've got the following document named "clients" which includes id, name and list of projects (array of objects):
{
"_id": {
"$oid": "572225d997bb651819f379f7"
},
"name": "ppg",
"projects": [
{
"name": "aaa",
"job_description": "",
"projectID": 20
},
{
"name": "bbbb",
"job_description": "",
"projectID": 21
}
]
}
I would like to update "job_description" of project with given "projectID" like this:
module.exports.saveJobDesc = function(client, idOfProject, textProvided) {
db.clients.update({ name: client},
{ $set: {'projects.0.job_description': textProvided }});
};
But instead of hardcoded index "0" of array I want to find specific project using "projectID". Is there a way to achieve this without changing the structure of collection and/or document?
If you want to update the "job_description" where name="ppg" and project_id=20 then you can use below mongo query:-
db.clients.update({ "name":"ppg","projects.projectID":20 },{$set: {"projects.$.job_description": "abcd"}})
Please let me know if any thing else is required
You cannot update multiple array elements in single update operation, instead you can update one by one which takes time depends upon number of elements in array and number of such documents in collection. see New operator to update all matching items in an array
db.test2.find().forEach( function(doc) {
var projects = doc.projects;
for(var i=0;i<projects.length;i++){
var project = projects[i];
if(project.projectID == 20){
var field = "projects."+i+".job_description";
var query = {};
query[field] = "textasdsd";
db.test2.update({ _id: doc._id},{ $set:query});
}
}
})

Add array key value in Javascript

I have a network array like the following way
"network_contents": [
{
"facebook":"contents to all pages",
},
{
"twitter":"twiter contents",
},
{
"linkedin":"linked in contents",
}
]
I would like to add some keys to that array bases on its content. If it is facebook the key should be facebook, if it is twitter key should be twitter. But not sure how to do it.
My requirement is to access network array contents, but it may or may not content these facebook, twitter, linked in values. I need to access its values. When i assign a key value will be easy to fetch its contents. So i tried this way to loop through the array
message.network_contents.forEach( function (nwContent) {
if(nwContent.twitter) {
console.log('nw content', nwContent.twitter);
}
})
can i create an array in this foreach loop like the following way.
{
"data": [
{
"facebook": {
"facebook": "facebook content"
},
"twitter": {
"twitter": "twitter content"
}
}
]
}
Your help is much appreciated thanks
Implementation of what I said in the comment:
var oldsies = stuff.network_contents;
var newsies = stuff.network_contents = {};
oldsies.forEach(function(network) {
var name = Object.keys(network)[0];
newsies[name] = network;
});
You gave an example of a JS object and not a dictionary and therefore cant add key-values.
You need something like this:
var network_contents = [];
network_contents["facebook"] = {config1: {name:"config1", value:"value1"}};
network_contents["twitter"] = {config2: {name:"config2", value:"value2"}};
example:
network_contents["facebook"].config1.value; // will return "value1"
You can covert your object to a dictionary easily.

Categories