Javascript/Jquery OOP Array inside of an Array - javascript

In a nutshell I am making a REST call to my database and getting a list of ingredients back. The JSON looks like:
[{"SubItemID":1,"MainItemID":1,"SubName":"2%","MainName":"Milk"},
{"SubItemID":2,"MainItemID":1,"SubName":"Skim/Fat Free","MainName":"Milk"},
{"SubItemID":3,"MainItemID":2,"SubName":"Chedder","MainName":"Cheese"}]
What I want to do is transform this into a useful array that is organized as:
Milk
2%Skim/Fat Free
Cheesechedder
In addition to it being ordered like that, I want to maintain the ID associated with each item. So cheese would have "2" and chedder would have "3".
I have been able to feed the unique values of Milk and Cheese into an array but I am not sure how to proceed. Advise would be appreciated!
Here's what I have so far:
$.ajax({
url: "../api/IngredientChoices",
contentType: "json",
success: function (data) {
var _subCategories = {};
var _mainCategories = [];
$.each(data, function (index, item) {
if ($.inArray(item.MainName, _mainCategories) === -1) {
_mainCategories.push(item.MainName);
}
});
$.each(_mainCategories, function () {
alert(this);
});
}
});

Detailed working answer. The data is added to an associative array.
obj = JSON.parse(data);
console.log(obj);
d = {}
$.each(obj, function (index, item) {
if (!(item.MainItemID in d)) {
d[item.MainItemID] = [];
d[item.MainItemID][0] = item.MainName;
d[item.MainItemID][1] = {}
}
d[item.MainItemID][1][item.SubItemID] = item.SubName;
});
console.log(d);
Output:
Object {1: Array[2], 2: Array[2]}
1: Array[2]
0: "Milk"
1: "2%"
2: "Skim/Fat Free"
2: Array[2]
0: "Cheese"
3: "Chedder"

You might want to edit your question. The 'useful' array you want is actually not an array. You might want this :
[
  {
   name : 'Milk',
   subTypes : [ '2%', 'Fat Free'],
  },
  {
   name : 'Cheese',
   subTypes : [ 'Cheddar' ],
  }
]

jsfiddle example
var data = [{"SubItemID":1,"MainItemID":1,"SubName":"2%","MainName":"Milk"},
{"SubItemID":2,"MainItemID":1,"SubName":"Skim/Fat Free","MainName":"Milk"},
{"SubItemID":3,"MainItemID":2,"SubName":"Chedder","MainName":"Cheese"}];
var ordered = {};
for(var i = data.length; i--;) {
var mainItemID = data[i].MainItemID;
if(!ordered[mainItemID]) {
ordered[mainItemID] = {};
ordered[mainItemID].MainName = data[i].MainName;
ordered[mainItemID].MainItemID = mainItemID;
}
ordered[mainItemID][data[i].SubItemID] = data[i];
}
console.log(ordered);
And you can have a array with your object collection, that way you will be able to sort it:
var dataArray = [];
for(var k in ordered) {
dataArray.push(ordered[k]);
}
console.log(dataArray);
If you plan more complex data parsing, or manipulation, I would recommend some model/collection framework, like: Backbonejs, SpineJS, or even use webSQL or IndexedDB.

Related

Get values from nested array that are dynamically generated

I am working on a chrome plugin that fetches data. But now i have been running into a problem, I have been asked to put together a nested array with all the data I have retrieved but I have no clue on how to pull this off.
What i want to create:
var messagedata [{
time: messageTime,
Date: messageDate,
Text: messageText
{
time: messageTime,
Date: messageDate,
Text: messageText
}
}];
Note that I know how to create the above when I have the variables. That is not the problem. But in this case i do not know how to declare the variables for each message from the array that is generated.
What i need is a nested array for each message that is in the HTML. So the above example displays 2 arrays but it could be 54 for example.
Code i use to generate normal array:
adiv.innerHTML = cleanupDocString;
trs = adiv.querySelectorAll('tr[bgcolor="#FFFFFF"]');
trs.forEach(function(tr) {
var d = [];
tr.querySelectorAll("td")
.forEach(function(td) {
var img = td.querySelector("img"),
src = img && img.attributes.getNamedItem("src").value;
d.push(src || td.textContent);
});
msgs.push(d);
});
The code above puts this out in console (this example has 2 messages inside it, there are also arrays with 54 messages):
0:Array(6)
0:"2017-08-31T00:00:00"
1:"13:22"
2:"MessageType"
3:”ClientName"
4:"Subject "
5:"messageText"
length:6
proto:Array(0)
1:Array(6)
0:"2017-08-31T00:00:00"
1:"13:21"
2:" MessageType "
3: "ClientName"
4:" Subject "
5:" messageText "
lenth:6
proto:Array(0)
To make the question easier:
I need to know how i can put the data into a variable that i fetch from the array above. I just don't know how to do it so its dynamic.
What i tried:
var messageDate = msgs[0][0];
var messageTime = msgs[0][1];
var messageType = msgs[0][2];
var messageClient = msgs[0][3];
var messageSubject = msgs[0][4];
var messageText = msgs[0][5];
The above code works but only fetches the first message. I need all the messages that are on the page that is provided. I tried using a ID in the first [] but that also didn't give me the desired result.
Thanks for your help and patience in advance.
Output and code has been slightly edited so it hides personal information
i am assuming msgs is arrray of arrays and the order of properties is guaranteed
var mappedArray = msgs.map((msg)=> {
return {
messageDate : msg[0];
messageTime : msg[1];
messageType : msg[2];
messageClient : msg[3];
messageSubject : msg[4];
messageText :msg[5];
}
})
Edit1
you can use arrayconcat
var mergedArray = mappedArray.concat(otherArray);
To transform the multidimensional array to an array of objects with the help of Array.prototype.map and a simple helper dictionary which defines the index => property mapping.
var messages = [
[
"2017-08-31T00:00:00",
"13:22",
"MessageType",
"ClientName",
"Subject",
"messageText",
"unwanted value"
],
[
"2017-08-31T00:00:00",
"13:22",
"MessageType",
"ClientName",
"Subject",
"messageText",
"unwanted value"
],
[
"2017-08-31T00:00:00",
"13:22",
"MessageType",
"ClientName",
"Subject",
"messageText",
"unwanted value"
]
];
var mappingDef = {
0: 'messageDate',
1: 'messageTime',
2: 'messageType',
3: 'messageClient',
4: 'messageSubject',
5: 'messageText'
};
function transformMessages(messages, mappingDef) {
return messages.map(function(message) {
var obj = {};
for(var index in mappingDef) {
if(mappingDef.hasOwnProperty(index)) {
obj[mappingDef[index]] = message[index];
}
}
return obj;
});
}
console.log(transformMessages(messages, mappingDef));

Json Filtering in jquery

Hello i want to filter json data like sql query without the help of plugins like alasql.js or linq.js or any plugins.
for example
{
"Managing PCL": [
{
"idItScreen": "1436",
"topicName": "Managing PCL",
"isFav": 0,
"cdeItScreen": "ListActiveTarif",
"busScreenName": "My Current Tarif"
},
{
"idItScreen": "1437",
"topicName": "Managing PCL",
"isFav": 0,
"cdeItScreen": "ListTermineTarif",
"busScreenName": "History Tarif"
}
]
}
for example i need to get data where idItScreen>1430 so that json data must be displayed the main challenge is to do without plugins so please reccomend me a good solution to do this without plugins
First turn your JSON into a Javascript object:
var obj = JSON.parse(myJSON);
Then do your filtering:
var matches = [];
var arr = obj['Managing PCL'];
for (var i = 0; i < arr.length; i++) {
if (arr[i].idItScreen > 1430) {
matches.push(arr[i]);
}
}
Or using jQuery.grep:
var matches = jQuery.grep(obj['Managing PCL'], function(n, i) {
return n.idItScreen > 1430;
});
Now matches contains the matching items.
If you want to get the JSON again, just use JSON.stringify:
var filteredJSON = JSON.stringify({'Managing PCL': matches});
You can also simply use .filter:
var matches = [];
var all = obj['Managing PCL'];
var filtered = all.filter(function(){
return $(this).idItScreen > 1430;
})
You don't need to use jQuery for this. You can use the filter() method of Array.prototype. See the working snippet below:
var obj = {
"Managing PCL": [{
"idItScreen": "1436",
"topicName": "Managing PCL",
"isFav": 0,
"cdeItScreen": "ListActiveTarif",
"busScreenName": "My Current Tarif"
}, {
"idItScreen": "1437",
"topicName": "Managing PCL",
"isFav": 0,
"cdeItScreen": "ListTermineTarif",
"busScreenName": "History Tarif"
}]
};
var filteredArray = obj['Managing PCL'].filter(function(item) {
return item.idItScreen > 1430;
});
obj['Managing PCL'] = filteredArray;
document.getElementById('result').innerHTML = JSON.stringify(obj);
<div id="result"></div>
You don't need jQuery for this. Use filter on the data instead.
function filterData(data, key, value) {
return data.filter(function (el) {
return el[key] > value;
});
}
// Note, `filter` operates on arrays, so you need to specify the
// array that contains the data
var result = filterData(data['Managing PCL'], 'idItScreen', '1430');
Also note that filter returns a new array containing the objects that it's found that match your criteria. You can access those objects in the usual way: result[0], for example.
DEMO
You could even expand this to create a function that returns data based on the operator too, not just greater-than, by using a look-up object:
var lookup = {
'>': function (data, value) { return data > value; },
'<': function (data, value) { return data < value; },
'===': function (data, value) { return data === value; }
}
function filterData(data, key, operator, value) {
return data.filter(function (el) {
return lookup[operator](el[key], value);
});
}
filterData(data['Managing PCL'], 'idItScreen', '>', '1430');
filterData(data['Managing PCL'], 'idItScreen', '===', '1430');
DEMO

Best way to store this data (array, object, etc)

I need to store (many) objects or arrays of data, which need to have the following criteria:
I need to be able to add a new set of data into the existing data easily
I need to be able to sort the data by date/ time added easily (array in order of when entries were pushed to it)
I need to be able to grab an entry easily using a reference, either integer or string. This is important, at the moment I have to do an $.each() to loop through my data until I find the entry I want.
I have tried using a structure like:
saved_info = {
1001: {//all my data for ref 1001},
1002: {//all my data for ref 1002}
}
which gave me what wanted of being able to grab the info easily given a reference:
info = saved_info[1001];
however, the reference numbers I use aren't in order - I use a reference given to me (its a unique identifier), therefore the object isn't in order of when items were added/saved/pushed.
You can use two objects:
One that stores the data by key
Another that stores the sort order
This way you can (i) lookup an element by key (ii) loop over elements in the order they were inserted. Rough outline of the structure:
var DataObject = {
data: {},
sort: []
};
Here is how you add data to this structure:
DataObject.data[1004] = {name: "Test 4"};
DataObject.sort.push(1004);
DataObject.data[1001] = {name: "Test 1"};
DataObject.sort.push(1001);
DataObject.data[1003] = {name: "Test 3"};
DataObject.sort.push(1003);
DataObject.data[1002] = {name: "Test 2"};
DataObject.sort.push(1002);
Here is how you perform a random access:
console.log(DataObject.data[1001].name);
console.log(DataObject.data[1003].name);
And here is how you iterate over all elements in the order they were added:
var i;
for (i = 0; i < DataObject.sort.length; i++) {
console.log(DataObject.data[DataObject.sort[i]].name);
}
It is possible to wrap the entire logic inside a class:
function DataObject() {
this.data = {};
this.sort = [];
this.setItem = function (k, v) {
this.data[k] = v;
this.sort.push(k);
};
this.getItemByKey = function (k) {
return this.data[k];
};
this.getItemByPos = function (i) {
return this.data[this.sort[i]];
};
this.getAllItems = function () {
var i, r = [];
for (i = 0; i < this.sort.length; i++) {
r.push(this.data[this.sort[i]]);
}
return r;
};
}
var t = new DataObject();
t.setItem(1001, {name: "Test 1"});
t.setItem(1002, {name: "Test 2"});
t.setItem(1003, {name: "Test 3"});
t.setItem(1004, {name: "Test 4"});
console.log(t.getItemByKey(1001));
console.log(t.getItemByPos(0));
console.log(t.getAllItems());
Try to build a Json like this,
var xJson = {
"1001":{//all my data for ref 1001},
"1002":{//all my data for ref 1002}
};
and you can fetch the records as per your wish using the bracket notation, since we are using a numeric value as a key.
var xData = xJson["1001"];

Finding object in nested collection with Underscore.js

I have a collection of teams (in a league) like so:
var fra1 = {
"sports":[
{
"name":"soccer",
"id":600,
"uid":"s:600",
"leagues":[
{
"name":"French Ligue 1",
"abbreviation":"fra.1",
"id":710,
"isTournament":false,
"country":{
"id":7,
"name":"France",
"abbreviation":"FRA"
},
"uid":"s:600~l:710",
"groupId":9,
"shortName":"Ligue 1",
"teams":[
{
"id":159,
"uid":"s:600~t:159",
"location":"Bordeaux",
"name":"Bordeaux",
"nickname":"Bordeaux",
"abbreviation":"BOR",
"color":"00003e",
},
{
"id":160,
"uid":"s:600~t:160",
"location":"Paris Saint-Germain ",
"name":"Paris Saint-Germain ",
"nickname":"Paris Saint-Germain ",
"abbreviation":"PSG",
"color":"000040",
}
]
}
]
}
],
}
There are about 20 teams in each var stored in this way. Then, I have about six such leagues: eng1, esp1, fra1, ger1, ita1, and usa1. I put those in another collection, like so:
var all = {
"eng1":eng1,
"esp1":esp1,
"fra1":fra1,
"ger1":ger1,
"ita1":ita1,
"usa1":usa1
}
Now, each team (regardless of the league they're in) has a unique ID: in the above example, Bordeaux has ID 159, PSG has ID 160, and so on. So I want to be able to search the all collection for a unique team by teamid, using Underscore.js, but I can't quite get the syntax down. I know I could search one league like so:
var obj = _.find(fra1.sports[0].leagues[0].teams, function(obj) { return obj.id == teamid })
But I can't figure out how to do it across all six leagues. Can anyone help? I'd prefer not to have to combine the collections into one manually, that would be cumbersome with the amount of data involved.
EDIT: I'm currently using:
for (var league in all)
{
var obj = _.find(all[league].sports[0].leagues[0].teams, function(obj) { return obj.id == teamid })
if (obj !== undefined)
{
// do things
}
}
But would still like something nicer.
One solution would be to create a map of the teams with the team id as the key and the team as the value:
var teams = {};
_.each(all, function(nation){
_.each(nation.sports[0].leagues[0].teams, function(team){
teams[team.id] = team;
});
});
You could then access the team using the key:
var psg = teams[160];
As far as parsing the rest of the teams, just use chain:
var allTeams = _.chain(all)
.values()
.pluck('sports').flatten() // once
.pluck('leagues').flatten() // twice
.pluck('teams').flatten() // third time's a charm
.value()
I would recommend using _.groupBy() on teamID. This will give you a hash-table (JS object) that maps teamID -> teamObject. Say you have your teams parsed like this:
var allTeams =[
{
"id":159,
"uid":"s:600~t:159",
"location":"Bordeaux",
"name":"Bordeaux",
"nickname":"Bordeaux",
"abbreviation":"BOR",
"color":"00003e",
},{
"id":160,
"uid":"s:600~t:160",
"location":"Paris Saint-Germain ",
"name":"Paris Saint-Germain ",
"nickname":"Paris Saint-Germain ",
"abbreviation":"PSG",
"color":"000040",
}]
You can group them with:
var lookup = _.groupBy(teams, 'id')
And then look up a team like this:
var myTeam = lookup[teamId]
Simply do additional loops over the sports and leagues, not only over all:
for (var league in all) {
var sports = all[league];
for (var i=0; i<sports.length; i++) {
var leagues = sports[i].leagues;
for (var j=0; j<leagues.length; j++) {
var teams = leagues[j].teams;
// var obj = _.find(teams, function(obj) { return obj.id == teamid })
for (var k=0; k<teams.length; k++) {
var obj = teams[k];
if (obj.id == teamid) {
… // do things
}
}
}
}
}

how to get distinct values from json in jquery

I've got a jquery json request and in that json data I want to be able to sort by unique values. so I have
{
"people": [{
"pbid": "626",
"birthDate": "1976-02-06",
"name": 'name'
}, {
"pbid": "648",
"birthDate": "1987-05-22",
"name": 'name'
}, .....
So, far, i have this
function(data) {
$.each(data.people, function(i, person) {
alert(person.birthDate);
})
}
but, I am at a total loss as to how efficiently get only the unique birthDates, and sort them by year (or any sort by any other personal data).
I'm trying to do this, and be efficient about it (i'm hoping that is possible).
Thanks
I'm not sure how performant this will be, but basically I'm using an object as a key/value dictionary. I haven't tested this, but this should be sorted in the loop.
function(data) {
var birthDates = {};
var param = "birthDate"
$.each(data.people, function() {
if (!birthDates[this[param]])
birthDates[this[param]] = [];
birthDates[this[param]].push(this);
});
for(var d in birthDates) {
// add d to array here
// or do something with d
// birthDates[d] is the array of people
}
}
function(data){
var arr = new Array();
$.each(data.people, function(i, person){
if (jQuery.inArray(person.birthDate, arr) === -1) {
alert(person.birthDate);
arr.push(person.birthDate);
}
});
}
Here's my take:
function getUniqueBirthdays(data){
var birthdays = [];
$.each(data.people, function(){
if ($.inArray(this.birthDate,birthdays) === -1) {
birthdays.push(this.birthDate);
}
});
return birthdays.sort();
}

Categories