object.push(array) is not working - javascript

I am using for loop to get the units onebyone and inside loop I am getting the array of volumes like below. now I want to push that array to respective unit so I used push but here I am getting error.
My code is below
$scope.UnitDetails = [{
UnitId : "001"
Unit1 : "A"
Fields: [{"one" : "true","Isactive" : true },
{"two" : "false","Isactive" : true }
]
},
{
UnitId : "002"
Unit1 : "B"
Fields: [{"one" : "true","Isactive" : true },
{"two" : "false","Isactive" : true }
]
}]
for(i= 0; i < $scope.UnitDetails.length ; i++){
var volume = [];
volume.Volume_AL = eval($scope.VolumeFormula.AL);
volume.Volume_BL = eval($scope.VolumeFormula.BL);
volume.Volume_CL = eval($scope.VolumeFormula.CL);
volume.Volume_DL = eval($scope.VolumeFormula.DL);
$scope.UnitDetails[i].push(volume);
}
Can anyone find where i am doing mistake
EDIT
When I try as below then it is creating another array in object as below
for(i= 0; i < $scope.UnitDetails.length ; i++){
var volume = {};
volume.Volume_AL = eval($scope.VolumeFormula.AL);
volume.Volume_BL = eval($scope.VolumeFormula.BL);
volume.Volume_CL = eval($scope.VolumeFormula.CL);
volume.Volume_DL = eval($scope.VolumeFormula.DL);
$scope.UnitDetails.push(volume);
}
What I got
$scope.UnitDetails = [{
UnitId : "001"
Unit1 : "A"
Fields: [{"one" : "true","Isactive" : true },
{"two" : "false","Isactive" : true }
]
},
{
UnitId : "002"
Unit1 : "B"
Fields: [{"one" : "true","Isactive" : true },
{"two" : "false","Isactive" : true }
]
},
{
Volume_CL:0,
Volume_EQ:12,
Volume_PH:54,
Volume_RW: 24
}]
My Expected :
$scope.UnitDetails = [{
UnitId : "001"
Unit1 : "A"
Fields: [{"one" : "true","Isactive" : true },
{"two" : "false","Isactive" : true }
]
volume : [ {
Volume_CL:0,
Volume_EQ:12,
Volume_PH:54,
Volume_RW: 24
}]
},
{
UnitId : "002"
Unit1 : "B"
Fields: [{"one" : "true","Isactive" : true },
{"two" : "false","Isactive" : true }
]
volume : [ {
Volume_CL:0,
Volume_EQ:12,
Volume_PH:54,
Volume_RW: 24
}]
},
]

To achieve the desired result you could append the volume array dynamically to each element of $scope.UnitDetails:
for (var i = 0; i < $scope.UnitDetails.length; i++) {
$scope.UnitDetails[i].volume = [{
Volume_AL: eval($scope.VolumeFormula.AL),
Volume_BL: eval($scope.VolumeFormula.BL),
Volume_CL: eval($scope.VolumeFormula.CL),
Volume_DL: eval($scope.VolumeFormula.DL)
}];
}
Remark: The eval statement allows for execution of arbitrary javascript code and if the input is coming from your users you might want to ensure that it doesn't contain any malicious code before passing it to this function. Or even better do not use eval at all. Depending on your requirements you might find a more appropriate and restrictive function to achieve your goal. For example if you are expecting to evaluate only mathematical expressions written from your clients you might find a library designed exactly for this purpose rather than using the general purpose eval statement.

Related

How can I access(and convert) 'date' to Javascript?

Here is MongoDB scheme.
{
"_id" : ObjectId("222222"),
"active" : false,
"amount" : "15%",
"description" : "15% discount",
"name" : "20200628-test",
"policies" : {
"apply" : [
{
"name" : "expiryDate",
"params" : {
"date" : ISODate("2020-07-06T14:59:59.999Z")
}
},
{
"name" : "isApplyCategoryExist"
}
],
"discount" : [],
"conflict" : [
{
"name" : "exclusive"
}
],
"grant" : []
},
"target" : {
"sku" : "",
"products_ids" : [],
"category_ids" : [
ObjectId("11111111")
]
},
"title" : "15% coupon"
}
I want to access date.
For example, "policies.apply.params.date"...
I don't know how to access 'date' to Javascript.
Please let me know...
apply is an array, so you have to give it index which you want to get.
var num = 0; // pick up an array number you want
var date = policies.apply[num].params.date;
Your policies.apply is an array so if you want to access "2020-07-06T14:59:59.999Z", you should do this:
policies.apply[0].params.date
But the "policies.apply[1]" doesn't have params (params.date also) so you can write a function to get date like this:
function get_apply_date(index) {
if(policies.apply[index].params && policies.apply[index].params.date)
return policies.apply[index].params.date;
return undefined; // or null
}

How to return sum of unknown fields' name?

I have data like this, and want to calculate how many i have true/false values for all fields
{
"key1" : true,
"key2" : false,
"key3" : true
},
{
"key1" : false,
"key2" : true,
"key3" : true
}
Expected result is
{
key1: { true: 1, false: 1 },
key2: { true: 1, false: 1 },
key3: { true: 2, false: 0 }
}
I can calc it for specific field with group by operator, but i don't know how to do this for all fields in collection
Closest you can get is this:
db.foo.aggregate([{
$group: {
_id: null,
key1 : {
$sum: {
$cond: {
if: "$key1",
then: 1,
else: 0
}
}
},
key2 : {
$sum: {
$cond: {
if: "$key2",
then: 1,
else: 0
}
}
},
key3 : {
$sum: {
$cond: {
if: "$key3",
then: 1,
else: 0
}
}
}
}
}])
Which will give you:
{
"_id" : null,
"key1" : 1,
"key2" : 1,
"key3" : 2
}
If you have no idea of the number of keys' name in you document, then you can't use the aggregation framework, instead what you need here is mapReduce and output the map reduce result into a new collection using the out option or display the result in the shell using inline: 1. Here we the option is used because we need extra processing step in order to get the expect result.
db.collection.mapReduce(
function() {
var keys = Object.keys(this);
for(var ind=0; ind<keys.length; ind++) {
if (keys[ind] !== "_id") {
var d = {};
d.name = keys[ind],
d.value= this[keys[ind]];
emit(d, 1);
}
}
},
function(key, values) { return Array.sum(values); },
{ "out": "mresult" }
)
which returns something like this:
{
"result" : "mresult",
"timeMillis" : 566,
"counts" : {
"input" : 2,
"emit" : 6,
"reduce" : 1,
"output" : 5
},
"ok" : 1
}
Five documents where saved in the newly created collection as shown by the mapReduce output. You can easily very this using the .find()
db.mresult.find()
which yields something like this:
{ "_id" : { "name" : "key1", "value" : false }, "value" : 1 }
{ "_id" : { "name" : "key1", "value" : true }, "value" : 1 }
{ "_id" : { "name" : "key2", "value" : false }, "value" : 1 }
{ "_id" : { "name" : "key2", "value" : true }, "value" : 1 }
{ "_id" : { "name" : "key3", "value" : true }, "value" : 2 }
As you can see even using mapReduce we can't get the expected result which is somehow a bit annoying, but these documents can easily be processed using the .aggregate method.
The first stage in you pipeline is the $project stage where you basically use the $cond conditional operator to "set" the value of "true" and "false". The last stage in the pipeline is the $group stage where you group your documents and use the $sum accumulator operator to return the sum for each group.
db.mresult.aggregate([
{ "$project": {
"true": {
"$cond": [
{ "$eq": [ "$_id.value", true ] },
"$value",
0
]
},
"false": {
"$cond": [
{ "$eq": [ "$_id.value", false ] },
"$value",
0
]
}
}},
{ "$group": {
"_id": "$_id.name",
"true": { "$sum": "$true" },
"false": { "$sum": "$false" }
}}
])
which produces something like this:
{ "_id" : "key3", "true" : 2, "false" : 0 }
{ "_id" : "key2", "true" : 1, "false" : 1 }
{ "_id" : "key1", "true" : 1, "false" : 1 }
Of course this is not exactly you expected output but much more better because, generally speaking using data as key is not a good idea.
I would go with callback passed to find query. it will give you more flexibility.
Sample.find({}, function (err, docs) {
if (!err) {
var result = {};
for (var i = 0; i < docs.length; i++) {
var currDoc = docs[i]._doc;
delete currDoc._id;
Object.keys(currDoc).forEach(function (key) {
var processedKey = result[key] ? result[key] : {"false": 0, "true": 0};
var count = (processedKey["" + currDoc[key]] | 0 ) + 1;
processedKey["" + currDoc[key]] = count;
result[key] = processedKey;
});
}
console.log(result);
process.exit();
} else {
throw err;
}
});
for input
[
{
"key1": true,
"key2": false,
"key3": true
},
{
"key1": true,
"key2": false,
"key3": true
}
]
It will output
{
key3: {
false: 0,
true: 2
},
key2: {
false: 2,
true: 0
},
key1: {
false: 0,
true: 2
}
}

Read data from arrays in javascript

I'm trying to read data from an array in JSON with javascript but I can't get it working. This is the segment of the JSON file from wich I want to read the data, I want to read the age variable from different arrays:
{
"failCount" : 1,
"skipCount" : 15,
"totalCount" : 156,
"childReports" :
[
{
"result" :
{
duration : 0.97834,
empty : false,
suites :
[
cases :
[
{
"age" : 0,
"status" : Passed
}
{
"age" : 15,
"status" : Passed
}
{
"age" : 3,
"status" : failed
}
]
]
}
}
]
}
I've tried this:
for (var i = 0; i < jsonData.childReports.suites.cases.length; i++)
{
var age = jsonData.childReports.suites.cases[i];
}
But it doesn't work. What would be the best way to do this?
Thanks in advance,
Matthijs.
Try the following code:
for (var i = 0; i < jsonData.childReports[0].result.suites[0].cases.length; i++) {
var age = jsonData.childReports[0].result.suites[0].cases[i].age;
}
Correct Json:
{
"failCount" : 1,
"skipCount" : 15,
"totalCount" : 156,
"childReports" : [
{
"result" : {
duration : 0.97834,
empty : false,
suites : [{
cases : [
{
"age" : 0,
"status" : "Passed"
},
{
"age" : 15,
"status" : "Passed"
},
{
"age" : 3,
"status" : "failed"
}
]}
]
}
}]
}
This way you can achieve that :
var data = {
"failCount" : 1,
"skipCount" : 15,
"totalCount" : 156,
"childReports" : [
{
"result" : {
duration : 0.97834,
empty : false,
suites : [{
cases : [
{
"age" : 0,
"status" : "Passed"
},
{
"age" : 15,
"status" : "Passed"
},
{
"age" : 3,
"status" : "failed"
}
]}
]
}
}]
};
for (var i = 0; i < data.childReports[0].result.suites[0].cases.length; i++) {
console.log(data.childReports[0].result.suites[0].cases[i].age);
}
DEMO

Json Array object to string logic

Not sure if I'm repeating the question or concept.
How do I convert the below sample to the below string format (may not be correct JSON format)
[{ "Name":"Test1","check":"true},{ "Name":"Test2","check":"true},{ "Name":"Test3","check":"false"}]
string format with appending - for false
Expected o/p:
"Test1","Test2","-Test3"
I have tried concatenating, but it always ends up with
"Test1,Test2-Test3"
But I am looking for 3 separate string separated by comma. Any hint would help
You can simply iterate through your array and collect the object in your required format:
var obj = [{
"Name" : "Test1",
"check" : true
}, {
"Name" : "Test2",
"check" : true
}, {
"Name" : "Test3",
"check" : false
}
];
var result = obj.map(function(x) {
return x.check ? x.Name : "-" + x.Name;
});
document.body.innerHTML = JSON.stringify(result);
Note that I have changed the format of your JSON in order to make it valid.
Just in case if you actually have a string true and false, and you can't change this, you can simply compare it as a string:
var obj = [{
"Name" : "Test1",
"check" : "true"
}, {
"Name" : "Test2",
"check" : "true"
}, {
"Name" : "Test3",
"check" : "false"
}
];
var result = obj.map(function(x) {
return x.check === 'true' ? x.Name : "-" + x.Name;
});
document.body.innerHTML = JSON.stringify(result);
HTML
<div id="output"></div>
Javascript
var obj = [{
"Name" : "Test1",
"check" : true
}, {
"Name" : "Test2",
"check" : true
}, {
"Name" : "Test3",
"check" : false
}
];
function getNames(){
var length=obj.length;
// alert(length);
var op=[];
for(var i=0;i<obj.length;i++){
// alert(obj[i].Name);
op[i]='"'+obj[i].Name+'"';
}
document.getElementById("output").innerHTML=op;
}
getNames();
Your output is there as expected.
Just loop through the valid JSON array(obj) and append the required values(obj.Name) to the empty string(str) based on the condition(appending '-' for 'false' value of obj.check).
var obj = [{
"Name" : "Test1",
"check" : true
}, {
"Name" : "Test2",
"check" : true
}, {
"Name" : "Test3",
"check" : false
}
];
var str = '';
for(var x in obj){
str += (obj[x].check === true) ? obj[x].Name : '-'+obj[x].Name;
str += (x != (obj.length-1)) ? ',' : '';
}
alert(str);

merging two data structures of different shapes

I have two data structures with different shapes that come from two different API's. The data is in JSON format, language is JavaScript.
Array 1:
[ { "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_1" },
"tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_1" },
{ "html" : "some_html", "name" : "TASK_NAME_2" } ] },
{ "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_2" },
"tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_3" },
{ "html" : "some_html", "name" : "TASK_NAME_4" } ] }]
Array 2:
[ [ { "name" : "TASK_NAME_1", "status" : "FINISHED" },
{ "name" : "TASK_NAME_2", "status" : "OPEN" } ],
[ { "name" : "TASK_NAME_3", "status" : "OPEN" },
{ "name" : "TASK_NAME_4", "status" : "FUTURE" } ] ]
The elements of the tooltips field from the array 1 contain the same "name"s as elements of array 2. How can I elegantly merge "status" from the array 2 into tooltips within array 1?
I thought that lenses could be the right answer, but I'm unsure as I've never used them.
I am aware of some ways I could solve it using nested iteration and updating array 1. I am ideally looking for an approach that doesn't modify existing data structures.
This is little complex but it should work for you
array2.forEach(function(tooltips){
tooltips.forEach(function(tooltip){
for (var i = 0; i < array1.length; i++) {
for (var j = 0; j < array1[i].tooltips.length; j++) {
var arr1Tooltip = array1[i].tooltips[j];
if(arr1Tooltip.name == tooltip.name)
arr1Tooltip.status = tooltip.status;
};
};
});
});
console.log(JSON.stringify(array1));
This is probably way over engineered and not very efficient, but you can do it as with this JSFiddle using recursive functions. I'm too tired to do it in a clever way.
var arr1 = [ { "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_1" },
"tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_1" },
{ "html" : "some_html", "name" : "TASK_NAME_2" } ] },
{ "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_2" },
"tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_3" },
{ "html" : "some_html", "name" : "TASK_NAME_4" } ] }];
var arr2 = [ [ { "name" : "TASK_NAME_1", "status" : "FINISHED" },
{ "name" : "TASK_NAME_2", "status" : "OPEN" } ],
[ { "name" : "TASK_NAME_3", "status" : "OPEN" },
{ "name" : "TASK_NAME_4", "status" : "FUTURE" } ] ];
var findStatus = function(name, searchArray) {
var r = '';
if (typeof searchArray === 'object') {
if ("name" in searchArray && "status" in searchArray) {
if (searchArray.name == name) {
return searchArray.status;
} else {
return '';
}
} else {
for (var i in searchArray) {
r = findStatus(name, searchArray[i]);
if (r != '') {
return r;
}
}
}
}
return '';
};
var updateStatus = function(arrToUpdate, arrWithStatus) {
var copy = $.extend(true, {}, arrToUpdate);
var r = '';
if (typeof copy === 'object') {
if ("name" in copy) {
r = findStatus(copy.name, arrWithStatus);
if (r != '') {
copy.status = r;
}
} else {
for (var i in copy) {
copy[i] = updateStatus(copy[i], arrWithStatus);
}
}
}
return copy;
};
var arr3 = updateStatus(arr1, arr2); // Final combined array
I added the var copy = $.extend(true, {}, arrToUpdate); line so that it will do a deep copy and not modify the original array, as a result, it requires jQuery.
Since your data structure is nested, you will need two zip.map/zipWiths:
zip(array1, array2).map(function([obj, tooltips]) { // ES6 destructuring syntax
return {
document: obj.document,
tooltips: zip(obj.tooltips, tooltips).map(function([tooltip, extender]) {
return {
html: tooltip.html,
name: tooltip.name,
status: extender.status
};
})
};
})
If you don't like to repeat those object literal structures, you might be able to use some copying function; for example
extend({}, document, {tooltips:…})
extend({}, tooltip, extender);
You also might use a lenses library like https://github.com/DrBoolean/lenses or https://github.com/fantasyland/fantasy-lenses for that, but I'm not sure whether that's worth the effort - the above code only needs underscore/lodash.
To get around the inner zipWith, you would need a Traversal lens (I assume you're familiar with this article), but I haven't yet seen a JavaScript library that offers such.

Categories

Resources