If laptop model and serial id are same, i've to add new field totalModel and increase count. For example in below case: serialid "1" and laptop model "xyz" are coming two time so i want to add "totalModel" count as 2 and so on. How can i achieve this in jquery
This question is not really about jQuery, it is about mapping and filtering arrays and objects. However, we can use some jQuery convenience methods to solve it.
A large part of solving these problems is by properly defining what you want to do. It sounds from your question that you want to get a map of unique serial ids per laptop model type. We can use JavaScript's Array.prototype.reduce to produce just such a map (Note that we will take the 'sold' value for the first of each laptop model we encounter):
var laptop_models = data.reduce(function (memo, obj) {
if (!memo[obj.laptopModel]) {
memo[obj.laptopModel] = {
unique_serial_ids: [],
sold: obj.sold
};
}
if ($.inArray(obj.serialid, memo[obj.laptopModel].unique_serial_ids) === -1) {
memo[obj.laptopModel].unique_serial_ids.push(obj.serialid);
}
return memo;
}, {});
Next, we can map our laptop_models object into the array you specified as your expected result:
var result = $.map(laptop_models, function (laptop_model, model_name) {
return {
laptopModel: model_name,
totalModel: laptop_model.unique_serial_ids.length,
sold: laptop_model.sold
};
});
You got the idea already. Iterate through the array.
if them item is in a hash, increment the count, otherwise, add to the hash and set the count to 1
var hash = {};
for (var i = 0;i<data.length;i++) {
if (hash[data[i].laptopModel) {
hash[data[i].laptopModel]++;
}
else
hash[data[i].laptopModel] = 1;
}
var data = [
{
"serialid": 1,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 5
},
{
"serialid" :1,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 4
},
{
"serialid": 1,
"laptopModel": "abc",
"sold": "yes",
"cnt": 3
},
{
"serialid": 3,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 2
}];
var result = []; //work if result = {};
var tempArray = []; // used to store unique name to prevent complex loop
data.forEach(function(item){
if($.inArray(item.laptopModel, tempArray)< 0){// unique name
result.push(formatData(item));
tempArray.push(item.laptopModel);
}
else{
var indexNew = $.inArray(item.laptopModel, tempArray);
result[indexNew]["totalModel"] += 1;
}
});
function formatData(item){
return{
"laptopModel": item.laptopModel,
"sold": item.sold,
"totalModel": 1
}
}
alert(JSON.stringify(result)); //expect array 2 item but it's empty array
console.log(result); //Will have result 2 item when I view console window
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Related
I am new to JS, I have been working on this case for 2 days now, experimenting how to get a value from a nested array by index.
This is my original array return from a server:
[
{
"customer":{
"c_id":"4047",
"quote_id":"PO3640",
"post_date":"2021-01-25 06:26:01",
"first_name":"Brett",
"last_name":"H",
"email":"brett#hafs.com.au",
"phone":"0419778645",
"postcode":"4128",
"state_address":null,
"message":"",
"computed_price":"4102.00",
"quote_source":"Piranha Off Road website",
"follow_up":null,
"follow_up_date":null
}
},
{
"vehicle":{
"v_id":"4220",
"make":"Toyota",
"model":"Hilux",
"year":"2020",
"cab_type":"Single Cab",
"engine":"Petrol",
"vehicle_feature":"Reverse Camera ",
"fitting_location":"Brisbane, QLD 4014",
"quote_id":"PO3640"
}
},
{
"traycanops":{
"id":"3974",
"product":"Steel UTE Tray",
"installation":"Piranha Branch",
"tray_size":"2400L x 1825W x 260H",
"tray_color":"Black",
"tub_removal":"Please remove my tub as part of installation",
"drivetrain":"2WD",
"tail_lights":"Standard Globe Light",
"claim_tub":null,
"get_tray_floor":null,
"canopy_size":null,
"canopy_color":null,
"paint_color":null,
"paint_code":null,
"canopy_type":null,
"floor_type":null,
"window_type":null,
"deck_type":null,
"doors":null,
"jack_off_style":null,
"canopy_finish":null,
"bundle":"false",
"powdercoat":"No",
"powdercoat_ac":null,
"quote_id":"PO3640",
"base_price":"$4102.00"
}
},
{
"accessories":null
}
]
Here's what I have done:
I did var result = JSON.parse(data); then var customer = JSON.parse(JSON.stringify(result[0])); and it gives me this:
I tried:
var customerdata = [];
$.each(customer, function(arrkey, arritem) {
customerdata.push(customerdata[arrkey]=arritem);
});
console.log(customerdata);
but it gives me this:
I just want something like customer.c_id instead of using loop. is this possible?
Thanks to https://stackoverflow.com/users/9513184/iota and https://stackoverflow.com/users/7941251/superstormer , I solve this by:
var result = JSON.parse(data);
console.log(result[0].customer.c_id);
//result: 4047
I am pushing Objects to a $localStorage array for persistence. I also check this array to see if an object is present before adding / removing an Object (if present it should splice if not present then it will push).
When I refresh my page the data returned from $localStorage doesn't seem to be the same as it was pre-refresh as my check function doesn't work, despite it looking EXACTLY the same on inspection.
Objects being pushed are structured like this:
{
"createdAt": "2015-04-24T10:21:21.649Z",
"difficulty": "Hard",
"exerciseDescription": "Lie on your back on a bench and take hold",
"exerciseID": "3101",
"exerciseName": "Bench Press",
"images": [8679, 8680, 8682],
"tags": ["Barbell", "Horizontal Flexion", "Extension", "Strength", "Chest", "Triceps", "Shoulder", "Elbow, Wrist & Hand"],
"updatedAt": "2015-09-09T20:14:59.681Z",
"words": ["bench", "press", "chest"],
"objectID": "ak6t7ukQdY",
"_highlightResult": {
"exerciseName": {
"value": "Bench Press",
"matchLevel": "none",
"matchedWords": []
}
}
}
Check if object if present (toggle add/remove)
$scope.addExerciseToProgramme = function(exercise) {
if (!$localStorage.Programme) {
$localStorage.Programme = [];
}
var index = $localStorage.Programme.indexOf(exercise);
if (index > -1) {
$localStorage.Programme.splice(index, 1);
} else {
$localStorage.Programme.push(exercise);
}
}
Function to watch/load $localStorage
$scope.$watch(function() {
return $localStorage.Programme
}, function(programme) {
$scope.programme = programme;
});
ng-class to check if exercise is in programme
<i class="exercise-add-indicator ion-ios-checkmark-outline" ng-class="{'orange': programme.indexOf(exercise) > -1}"></i>
Problem
There are two problems with this:
Following refresh, the ng-class doesn't conditionally add the class depending on the content of my $scope.programme
The addExerciseToProgramme function doesn't respect the indexOf check and pushes the exercise object to the array regardless!
Array.prototype.indexOf() uses strict equality: An expression comparing Objects is only true if the operands reference the same Object.
You shouldn't use this when working with localStorage.
When saving an object to localStorage it's turned into a string. When retrieved it's turned into an object again.
This will however be a new object, even if it looks exactly the same.
For example, this will yield false:
var object1 = { id: 1 };
var object2 = { id: 1 };
console.log(object1 === object2);
To get it working you can implement a custom function that retrieves the index based on the value of a property of your choosing. Note that it should be unique.
For example:
$scope.getExerciseIndex = function(exercise) {
var index = -1;
if (!$scope.programme) return index;
for (var i = 0; i < $scope.programme.length; i++) {
if ($scope.programme[i].exerciseID !== exercise.exerciseID) continue;
index = i;
break;
}
return index;
};
$scope.exerciseExists = function(exercise) {
var index = $scope.getExerciseIndex(exercise);
return index > -1;
};
$scope.addExerciseToProgramme = function(exercise) {
if (!$localStorage.Programme) {
$localStorage.Programme = [];
}
var index = $scope.getExerciseIndex(exercise);
if (index > -1) $localStorage.Programme.splice(index, 1);
else $localStorage.Programme.push(exercise);
};
HTML:
... ng-class="{'orange': exerciseExists(exercise) }" ...
Demo: http://plnkr.co/edit/R6TEisvQ7gkDcwBgw0D1?p=preview
This question is in regards to javascript or jQuery, whichever will get the job done better.
What I want to do is create an object similar to the following:
var prodItems = [
{
"product": "prod1",
"item": ["prod1Item1", "prod1Item2"]
},
{
"product": "prod2",
"item": ["prod2Item1", "prod2Item2", "prod2Item3", "prod2Item4"]
}
];
with this I can access the members like this:
prodItems[1]["product"] is "prod2"
prodItems[1]["item"][0] is "prod2Item1"
I would like to create this list dynamically and I am stumbling with the syntax, something like:
var menuItems;
menuItems.product[0] = "prod1";
menuItems.product[0].item[0] = "prod1Item1";
Can someone please give me some guidance on how I can do this?
Edit, i want to create a function with something like
returnDict("prod2", "prod2Item3")
this will rearrange it like so:
prodItems = [
{
"product": "prod2",
"item": ["prod2Item3", "prod2Item1", "prod2Item2", "prod2Item4"]
},
{
"product": "prod1",
"item": ["prod1Item1", "prod2Item2"]
}
];
My "guidance" on constructing the object would be to avoid this style of inserting each string separately:
menuItems.product[0].product = "prod1";
menuItems.product[0].item[0] = "prod1Item1";
because this involves a lot of writing the same thing over and over, which is more error-prone and less readable/maintainable. I would prefer inserting more coarse-grained objects:
menuItems.product[0] = {
product: "prod1",
item: ["prod1Item1"];
}
Edit: Your edit is asking a completely different question, but it sounds like what you want to do is sort the elements of prodItems based on their "product" properties, then do the same thing for the "items" array inside the elements.
I think the simplest way to do this would be to use Array.sort() with a custom comparison function that returns -1 on the element you want to see at the top. Something like this (hastily written and untested):
function returnDict(product, item) {
prodItems = prodItems.sort(function(a, b) {
if(a.product === product) {
return -1;
} else if(b.product === product) {
return 1;
} else {
return 0;
}
});
prodItems[0].items = prodItems[0].items.sort(function(a, b) {
if(a === item) {
return -1;
} else if(b === item) {
return 1;
} else {
return 0;
}
});
return prodItems;
}
var menuItems = [];
menuItems.push({product:"prod1",item:[]})
menuItems[menuItems.length-1].item.push("product1Item1")
menuItems[menuItems.length-1].item.push("product1Item2")
menuItems.push({product:"prod2",item:[]})
menuItems[menuItems.length-1].item.push("product2Item1")
menuItems[menuItems.length-1].item.push("product2Item2")
menuItems[menuItems.length-1].item.push("product2Item3")
menuItems[menuItems.length-1].item.push("product2Item4")
var prodItems = [
{
"product": "prod1",
"item": ["prod1Item1", "prod2Item2"]
},
{
"product": "prod2",
"item": ["prod2Item1", "prod2Item2", "prod2Item3", "prod2Item4"]
}
];
alert(prodItems[0].product);
for(var i = 0; i < prodItems.length; i++) {
alert(prodItems[i].product);
}
I see your question has been answered, but I want to suggest a small improvement to keep your code more DRY (Do not Repeat Yourself). You can use a simple function that will save you some extra typing when adding new objects.
var prodItems=[];
function addProduct(productName, items){
var product={
product: productName,
items: items
};
prodItems.push(product);
};
//sample use
addProduct("prod2",["prod2Item3", "prod2Item1", "prod2Item2", "prod2Item4"])
This will definitely also become more flexible if you need to change the object structure at some later point.
I have collection named inventory where I have multiple documents that has values for each doc
{ "apples": 2 ,"oranges": 3, "carrots": 5 }
{ "apples": 4, "oranges": 6, "carrots": 9 }
How do I update push all fruits in to a single array on multiple documents like so:
{ "fruits": { "apples":2 ,"oranges":3 }, "carrots": 5 }
First thing to note here is that the example you give is not an array but just a sub-document for "fruits" that has different keys. An "array" in MongoDB would look like this:
{ "fruits": [{ "apples":2 } , { "orange":3 }], "carrot": 5 }
Also, aside from the term "fruits" being subjective, as with no other identifier you would have to specify a "list" of things that qualify as fruits, the other thing to consider is that there is no actual way in MongoDB at present to refer to the existing value of a field when processing an update.
What that means is you need to .find() each document to retrieve the data in order to be able to work with the sort of "re-structure" that you want. This essentially means looping the results an performing an .update() operation for each document.
The Bulk API for MongoDB 2.6 and greater can be of some help here, where at least the "write" operations to the database can be sent in batches, rather than one at a time:
var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;
var fruits = ["apples","oranges"];
var unset = {};
fruits.forEach(function(fruit) {
unset[fruit] = 1;
});
db.collection.find({}).forEach(function(doc) {
var fields = [];
fruits.forEach(function(fruit) {
if ( doc.hasOwnProperty(fruit) ) {
var subDoc = {};
subDoc[fruit] = doc[fruit];
fields.push(subDoc);
}
});
bulk.find({ "_id": doc._id }).updateOne({
"$unset": unset, "$push": { "fruits": { "$each": fields } }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
var bulk = db.collection.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
That also uses the $each modifier for $push in order to add multiple array entries at once. The $unset operator can be safely called for fields that don't exist in the document so there is no need to check for their presence in the document as is otherwise required when constructing the array of elements to $push.
Of course if you actually want a document like what you gave an example of that is not actually an array, then you construct differently with the $set operator:
var fields = {};
fruits.forEach(function(fruit) {
if ( doc.hasOwnProperty(fruit) )
fields[fruit] = doc[fruit];
});
bulk.find({ "_id": doc._id }).updateOne({
"$unset": unset, "$set": { "fruits": fields }
});
Whatever the case is you need to loop the existing collection. There is no operation that allows you to "take" an existing value in a document and "use it" in order to set a new value from a server side perspective.
I am working to fetch and analyze a large data set.
I want to know how many each value is appearing in the data set.
Let's give a small example to clarify things.
[
{"Year": "1997", "Company": "Ford", "Model": "E350", "Length": "2.34"},
{"Year": "2000", "Company": "Mercury", "Model": "Cougar", "Length": "2.38"}
{"Year": "2001", "Company": "Ford", "Model": "Cougar", "Length": "2.38"}
]
I don't know exactly what the values that I am having, but I want to hash it to get the results this way.
[
{"Value": "Ford", "Frequency": 2},
{"Value": "Mercury", "Frequency": 1},
]
In case it's not dynamic and I know the the values, I will do it this way:
var filteredCompany = data.filter(function(a) {
return /Ford/i.test(a.Company).lenght;
});
But, I have a very large data set (900 Mbo), I need to make this process in a very dynamic way.
UPDATE
var dataset = {}
d3.csv(link, function(data) {
dataset = data;
});
//Fetch data
var frequency = {};
var datasetlength = dataset.length;
for(var i = 0; i < datasetlength; i++){
var current = dataset[i];
if(!frequency.hasOwnProperty(current.company)) frequency[current.company] = 0;
frequency[current.company]++;
}
What you can do is loop through all the entries, and gather them into an object where the key is the name and the value is the count. The initial data will look like this:
{
"Ford" : 2,
"Mercury" : 1
}
You can do a reduce, passing through an object:
var frequency = hugeData.reduce(function(freq,current){
var currentCompany = current.Company;
if(!freq.hasOwnProperty(currentCompany)) freq[currentCompany] = 0;
freq[currentCompany]++;
return freq;
},{});
But reduce is ES5 and sometimes slow. You can do a plain loop:
var frequency = {};
var hugeDataLength = hugeData.length;
for(var i = 0; i < hugeDataLength; i++){
var current = hugeData[i];
var currentCompany = current.Company;
if(!frequency.hasOwnProperty(currentCompany)) frequency[currentCompany] = 0;
frequency[currentCompany]++;
}
Now that we have reduced the data into a much more manageable size, you can loop through the frequency data and turn it into an array, moving down the key and value into an object.
var chartData = Object.keys(frequency).map(function(company){
var value = frequency[company];
return {
Value : company,
Frequency : value
}
});
A running demo can be seen here.
I did a similar feat in the past few months, and your browser's debugger is a very handy tool for this job, especially the CPU profiler. You can pin down which operations are actually causing the lag.
I'm not sure if this is the most efficient method of going through that much data (then again, Javascript was not made for big data so efficiency shouldn't be on your mind).
Basically I would approach this looping through all the data with an associative array keeping track of the frequency. If the current data.Company is not in the associative array, it'll add it on to the array as a key and then input the frequency of one. If it is found as a key in the array, it'll increment the frequency by 1.
Example