scope in javascript.. parent scope variable not retaining value - javascript

I am a newbie to javascript..have gone thru multiple scope related blogs and several answers on stackoverflow..but not sure why this code doesnt work..
function checkPhoneEmail(element, index, array) {
var _contact = {};
var _phone_empty = true;
var _email_empty = true;
var _phones_to_store = [];
var _emails_to_store = [];
var _prev_phone_number;
var _phone;
var i;
//function to check if this phone
// should be included
function checkMobilePhone(ph_element) {
var _match;
_match = ph_element.type.match(/mobile/i);
if (_match && ph_element.value.length >= 10 && !(ph_element.value.match(/^800/) || ph_element.value.match(/^1800/) || ph_element.value.match(/^1-800/))) {
return true;
};
return false;
};
if (!_.isEmpty(element.phoneNumbers)) {
for (i = 0; i < element.phoneNumbers.length; i++) {
console.log('prev num: ' + _prev_phone_number);
console.log('curr num: ' + element.phoneNumbers[i].value)
if (!_.isEqual(_prev_phone_number, element.phoneNumbers[i].value)) {
if (checkMobilePhone(element.phoneNumbers[i])) {
_phone = {
id: element.phoneNumbers[i].id,
value: element.phoneNumbers[i].value
};
_phones_to_store.push(_phone);
console.log('phone to store: ' + element.phoneNumbers[i].value)
};
};
_prev_phone_number = element.phoneNumbers[i].value;
console.log('prev1 num: ' + _prev_phone_number);
};
_phone_empty = false;
};
if (!_.isEmpty(element.emails)) {
};
};
why is the _prev_phone_number not being set ? I see it at prev1 num..but when you look for the next element its set back to undefined...my understanding is for doesnt create a new scope ? is this incorrect ?
I am trying to remove duplicates from phone contacts array (from cordova contacts) and doing some very basic checks to eliminate all numbers except a valid us mobile # for a mobile app..using above logic if a contact has multiple entries in contacts for same phone number i am seeing duplicates..Tried above logic with foreach and also _.uniq ... but same result..
Any help is appreciated.
sample Data:
{
"id" : "1916",
"rawId" : "1911",
"displayName" : "John Doe",
"name" : {
"familyName" : "Doe",
"formatted" : "John Doe",
"givenName" : "John"
},
"nickname" : null,
"phoneNumbers" : [{
"type" : "mobile",
"value" : "+1 999 666 9175",
"id" : "11994",
"pref" : false
}, {
"type" : "mobile",
"value" : "+1 999 666 9175",
"id" : "12001",
"pref" : false
}
],
"emails" : null,
"addresses" : null,
"ims" : null,
"organizations" : null,
"birthday" : null,
"note" : "",
"photos" : null,
"categories" : null,
"urls" : null
}

Instead of using the variable _prev_phone_number, why don't you just access element.phoneNumbers[i-1].value? No need to introduce a new variable for it.
If that doesn't work, then something is clobbering your object and we will need to look deeper.

A for loop does not create its own scope. The issue is that you are trying to log to the console an undefined value.
for (i = 0; i < element.phoneNumbers.length; i++) {
//_prev_phone_number is undefined here.
console.log('prev num: ' + _prev_phone_number);
console.log('curr num: ' + element.phoneNumbers[i].value)
if (!_.isEqual(_prev_phone_number, element.phoneNumbers[i].value)) {
if (checkMobilePhone(element.phoneNumbers[i])) {
_phone = {
id: element.phoneNumbers[i].id,
value: element.phoneNumbers[i].value
};
_phones_to_store.push(_phone);
console.log('phone to store: ' + element.phoneNumbers[i].value)
};
};
//This is the first time you have defined _prev_phone_number
_prev_phone_number = element.phoneNumbers[i].value;
console.log('prev1 num: ' + _prev_phone_number);
};
You should probably check to see if _prev_phone_number has been defined before logging it to the console.
if(_prev_phone_number){
console.log('prev num: ' + _prev_phone_number);
}
This would ensure that you are not logging an undefined value.

Related

Can't Set MongoDB Document Field to Null

I am attempting to modify a collection via the mongo shell to trim all strings, then, if the field is a string but is numeric, change its data type to a number.
Here is the code I am using:
function isNumeric(num) {
return !isNaN(parseFloat(num)) && isFinite(num);
}
var bulk = db.yale.initializeOrderedBulkOp();
var counter = 0;
db.yale.find().forEach((doc) => {
let updoc = {
"$set" : {}
};
// get document fields but ignore immutable id field
let fields = Object.keys(doc);
let badField = fields.indexOf("_id");
if (badField > -1) {
fields.splice(badField, 1);
}
fields.forEach((field) => {
if (typeof doc[field] === "string") {
updoc["$set"][field] = doc[field].trim();
}
});
fields.forEach((field) => {
if (typeof doc[field] === "string") {
if (isNumeric(doc[field])) {
updoc["$set"][field] = parseFloat(doc[field]);
} else {
if (doc[field].length === 0) {
updoc["$set"][field] = null;
}
}
}
});
bulk.find({
"_id" : doc._id
}).update(updoc);
counter++;
if (counter % 1000 === 0) {
bulk.execute();
bulk = db.yale.initializeOrderedBulkOp();
}
});
(Note 1: the dataset is the Yale Bright Star catalog from the Vizier service, hence the name).
(Note 2: I prefer a isNumeric() function to !isNan() because I honestly think it looks better, personal preference)
Before the code is run, the first couple of results from db.yale.find() looks like this:
{ "_id" : ObjectId("5d945e8baea250effd9dd0dc"), "HR" : " 1", "Name" : " ", "HD" : " 3", "SAO" : " 36042", "ADS" : " 46", "VarID" : " ", "RAJ2000" : "00 05 09.9", "DEJ2000" : "+45 13 45", "Vmag" : " 6.70", "BV" : " 0.07", "SpType" : " A1Vn ", "NoteFlag" : "" }
{ "_id" : ObjectId("5d945e8baea250effd9dd0dd"), "HR" : " 11", "Name" : " ", "HD" : " 315", "SAO" : 128595, "ADS" : " ", "VarID" : "Var? ", "RAJ2000" : "00 07 44.1", "DEJ2000" : "-02 32 56", "Vmag" : " 6.43", "BV" : -0.14, "SpType" : " B8IIIpSi ", "NoteFlag" : "*" }
After the run, the first lines look like this:
{ "_id" : ObjectId("5d945e8baea250effd9dd0dc"), "HR" : 1, "Name" : "", "HD" : 3, "SAO" : 36042, "ADS" : 46, "VarID" : "", "RAJ2000" : "00 05 09.9", "DEJ2000" : "+45 13 45", "Vmag" : 6.7, "BV" : 0.07, "SpType" : "A1Vn", "NoteFlag" : null }
{ "_id" : ObjectId("5d945e8baea250effd9dd0dd"), "HR" : 11, "Name" : "", "HD" : 315, "SAO" : 128595, "ADS" : "", "VarID" : "Var?", "RAJ2000" : "00 07 44.1", "DEJ2000" : "-02 32 56", "Vmag" : 6.43, "BV" : -0.14, "SpType" : "B8IIIpSi", "NoteFlag" : "*" }
Notice that in the first Document, the "ADS" field has been converted to a number, but in the second Document, the "ADS" field is still an empty string, empty though it should have been converted to null.
I do not want to remove the field from the collection entirely. For the sake of the service that will be using it, the value of null means something.
Can anyone see an issue with the javascript that is causing the field not to convert to null? It's probably just a dumb error I am overlooking.
Jason

Firebase functions getChild value

I am having a problem on firebase functions. What I trying to do is when Items's child gets updated, then I want to get the value of Count and do further calculation, But what I am facing is that the firebase log console always shows an erreor "TypeError: Cannot read property 'val' of undefined".
JSON structure
"VTEST" : {
"A" : {
"Count" : 5,
"Items" : {
"item1" : "apple"
},
"NUMBER" : 5
},
"B" : {
"Count" : 8,
"Items" : {
"item1" : "orange;"
},
"NUMBER" : 3
},
"C" : {
"Count" : 10,
"Items" : {
"item1" : "grape"
},
"NUMBER" : 7
},
"D" : {
"Count" : 12,
"Items" : {
"item1" : "grava"
},
"NUMBER" : 10
},
"E" : {
"Count" : 15,
"Items" : {
"item1" : "fish"
},
"NUMBER" : 12
},
"F" : {
"Count" : 18,
"Items" : {
"item1" : "chicken;"
},
"NUMBER" : 8
}
}
My code:
exports.ItemCount = functions.database.ref('/VTEST/{ID}/Items').onUpdate((updateRef, context) => {
var childCount = updateRef.after.numChildren();
var newReference = updateRef.after.ref.parent.child('/Count');
var Count = newReference.val();
Count = Count + childCount;
return updateRef.ref.update({Count})
})
What I expect is the Count's value will be update, but it always show error : "TypeError: Cannot read property 'val' of undefined"
Can anyone tell me what am I doing wrong here, I don't get it.
The problem comes from the fact that a Reference does not have a val() method. You need to use the once() method to get the value of the corresponding database location.
The following adapted code should work:
exports.ItemCount = functions.database
.ref('/VTEST/{ID}/Items')
.onUpdate((updateRef, context) => {
var childCount = updateRef.after.numChildren();
var newReference = updateRef.after.ref.parent.child('/Count');
return newReference.once('value').then(dataSnapshot => {
var Count = dataSnapshot.val();
Count = Count + childCount;
return newReference.parent.update({ Count: Count });
});
});
However, depending on your exact requirements, you may decide to use a Transaction, see https://firebase.google.com/docs/database/web/read-and-write#save_data_as_transactions

How to Combine or Merge Object Array with Object Array Jquery

i have an object like this in my console:
ObjectName1 : Array(3)
0 : { id : 1, name : 'foo' },
1 : { id : 2, name : 'foo-2' },
2 : { id : 3, name : 'foo-3' },
ObjectName2 : Array(3)
0 : { id : 1, foo : 'bar' },
1 : { id : 2, foo-2 : 'bar-2' },
2 : { id : 3, foo-3 : 'bar-3' },
and as usually if we want to get the name, just write : ObjectName1[key].name right ?
now if i want to get the key from ObjectName2 (foo, foo-2, foo-3) how to get the key from ObjectName2 using the value from ObjectName1 ?
i have written like this :
// just say there is an each above this comment
var name = ObjectName1[key].name;
var bar = ObjectName2[key]+"."+name;
// end each
but it just showed
[Object object].foo
[Object object].foo-2
[Object object].foo-3
the output should be like this :
bar
bar-2
bar-3
it is possible doing like i want to do ? help me please if it is possible
any help will be very appreciated.
*note : i'm not sure what is the case name in my problem, so forgive me if the title went wrong
thanks
Try this one. Loop through each object in ObjectName1 object and get the name in appropriate index, this name will be the key for the ObjectName2 object. Then use that key to print the appropriate value from ObjectName2
var ObjectName1 = [{'id' : 1, 'name' : 'foo'}, {'id' : 2, 'name' : 'foo-2'}, {'id' : 3, 'name' : 'foo-3'}];
var ObjectName2 = [{'id' : 1, 'foo' : 'bar'}, {'id' : 2, 'foo-2' : 'bar-2'}, {'id' : 3, 'foo-3' : 'bar-3'}];
for(var i = 0; i < ObjectName2.length; i++){
console.log(ObjectName2[i][ObjectName1[i]['name']]);
}
Something like this?
var name = ObjectName1[key].name;
ObjectName2.forEach(function(a) {
if (a.keys().includes(name)) {
var bar = a[name];
// then do what you want with bar
}
}
As commented, your key is an object. Hence, it is showing [Object object].foo-3.
You will have to use 2 loops and check if the key is inside current object. If yes, print it, else continue.
var ObjectName1 =[
{ id : 1, name : 'foo' },
{ id : 2, name : 'foo-2' },
{ id : 3, name : 'foo-3' },
]
var ObjectName2 = [
{ id : 1, foo : 'bar' },
{ id : 2, 'foo-2' : 'bar-2' },
{ id : 3, 'foo-3' : 'bar-3' },
];
ObjectName1.forEach(function(obj){
ObjectName2.forEach(function(obj2){
var key = obj.name;
if(key in obj2){
console.log(obj2[key])
}
})
})
now if i want to get the key from ObjectName2 (foo, foo-2, foo-3) how to get the key from ObjectName2 using the value from ObjectName1 ?
If you know those are parallel arrays (where [0] in one array is intentionally a match for [0] in the other array), you can simply loop through:
ObjectName1.forEach(function(entry1, index) {
var value = ObjectName2[index][entry1.name];
console.log(entry1.name + " = " + value);
});
Example:
var ObjectName1 = [
{ id : 1, name : 'foo' },
{ id : 2, name : 'foo-2' },
{ id : 3, name : 'foo-3' }
];
var ObjectName2 = [
{ id : 1, "foo" : 'bar' },
{ id : 2, "foo-2" : 'bar-2' },
{ id : 3, "foo-3" : 'bar-3' }
];
ObjectName1.forEach(function(entry1, index) {
var value = ObjectName2[index][entry1.name];
console.log(entry1.name + " = " + value);
});
That assumes you know they're parallel arrays.
If not, you have to search for it. Array.prototype.findIndex will return the index of the first element where a callback returns true:
ObjectName1.forEach(function(entry1) {
console.log("entry1.name = " + entry1.name);
var index = ObjectName2.findIndex(function(entry2) {
// See if entry2 contains a key with that value
return entry1.name in entry2;
});
console.log(index == -1 ? "Not found" : ("Found at index #" + index + ", value = " + ObjectName2[index][entry1.name]));
});
Example:
var ObjectName1 = [
{ id : 1, name : 'foo' },
{ id : 2, name : 'foo-2' },
{ id : 3, name : 'foo-3' }
];
var ObjectName2 = [
{ id : 1, "foo" : 'bar' },
{ id : 2, "foo-2" : 'bar-2' },
{ id : 3, "foo-3" : 'bar-3' }
];
ObjectName1.forEach(function(entry1) {
console.log("entry1.name = " + entry1.name);
var index = ObjectName2.findIndex(function(entry2) {
// See if entry2 contains a key with that value
return entry1.name in entry2;
});
console.log(index == -1 ? "Not found" : ("Found at index #" + index + ", value = " + ObjectName2[index][entry1.name]));
});
If you don't really need the key (e.g., index) of the matching object in ObjectName2, just the object, use find instead:
ObjectName1.forEach(function(entry1) {
console.log("entry1.name = " + entry1.name);
var entry = ObjectName2.find(function(entry2) {
// See if entry2 contains a key with that value
return entry1.name in entry2;
});
console.log(!entry ? "Not found" : ("Found, value is " + entry[entry1.name]));
});
Example:
var ObjectName1 = [
{ id : 1, name : 'foo' },
{ id : 2, name : 'foo-2' },
{ id : 3, name : 'foo-3' }
];
var ObjectName2 = [
{ id : 1, "foo" : 'bar' },
{ id : 2, "foo-2" : 'bar-2' },
{ id : 3, "foo-3" : 'bar-3' }
];
ObjectName1.forEach(function(entry1) {
console.log("entry1.name = " + entry1.name);
var entry = ObjectName2.find(function(entry2) {
// See if entry2 contains a key with that value
return entry1.name in entry2;
});
console.log(!entry ? "Not found" : ("Found, value is " + entry[entry1.name]));
});

Compare array and remove unmatched values

$scope.locations = [
{ name : "One"},
{ name : "Two"},
{ name : "Three"},
{ name : "India"},
{ name : "Japan"},
{ name : "China"}
];
$scope.tempLocations = [
{ name : "One"},
{ name : "Two"},
{ name : "global"},
];
I have two arrays. If location doesn't contain some of the names in tempLocations I want to remove them from tempLocation. In this case i want to remove location Global
I tried the following, but does not work.
for(var i=0;i<$scope.tempLocations.length;i++){
var index = $scope.tempLocations.indexOf($scope.locations[i]);
if(index == -1){
console.log($scope.tempLocations[i]);
$scope.tempLocations.splice(i,1);
}
}
I guess you're looking for this
$scope = {}
$scope.locations = [
{ name : "One"},
{ name : "Two"},
{ name : "Three"},
{ name : "India"},
{ name : "Japan"},
{ name : "China"}
];
$scope.tempLocations = [
{ name : "One"},
{ name : "Two"},
{ name : "global"},
];
$scope.tempLocations = $scope.tempLocations.filter(function(x) {
return $scope.locations.some(function(y) {
return x.name == y.name
})
})
document.getElementById("output").innerHTML = JSON.stringify($scope.tempLocations, 0,' ');
console.log($scope);
<pre id="output"></pre>
If you have many (100+) locations, consider converting them to an "associative array" first, like:
validLocations = { "One": 1, "Two": 1 ... etc
You need to loop through manually as the comment from Paul S. suggests:
var locations = [
{ name : "One"},
{ name : "Two"},
{ name : "Three"},
{ name : "India"},
{ name : "Japan"},
{ name : "China"} ];
var tempLocations = [
{ name : "One"},
{ name : "Two"},
{ name : "global"},
];
var newTempLocations = tempLocations.filter(function(temp){
return locations.some(function(location){ // stop and return true at first match
return location.name === temp.name;
});
})
// print output
document.getElementById("output").innerHTML = JSON.stringify(newTempLocations, null, " ");
<pre id="output"></pre>
If $scope.locations isn't going to change often, you could do the following:
Build a lookup table for locations
var location_lookup = {};
for ( var i = 0; i < $scope.locations.length; i++ ) {
location_lookup[$scope.locations[i].name] = true;
}
Filter based on the existence of a key
$scope.filteredLocations = $scope.tempLocations.filter(function(temp) {
return location_lookup.hasOwnProperty(temp.name);
});
This will prove to be much faster if you're filtering more often than you need to recompute the lookup. So if $scope.locations is static, this would be a good route.
I would advise against using temp.name in location_lookup as another poster said to since that will also check ALL of the prototyped properties of the location_lookup object. For instance, if another script in your app did Object.prototype.global = function(){} then the filter would return "global" as being part of $scope.locations, which is not the behavior you want. hasOwnProperty will only check the object itself and not any prototypical inheritance while also being a more efficient method.
Fiddle Demonstration: http://jsfiddle.net/cu33ojfy/ (also included an implementation that uses Array.prototype to add a .filter_locations() method, but adding to Array.prototype is generally a bad idea)

Iterating over a JavaScript object in sort order based on particular key value of a child object

Short version: I'm looking for the JavaScript equivalent of Perl's
for my $key ( sort { $hash{$a}{foo} cmp $hash{$b}{foo} } keys %hash ) {
# do something with $key
}
More detail:
I have a JSON object which consists of a bunch of other JSON objects which have identical properties to each other, like a hash of hashes in Perl: eg:
var peopleobj = {
"0291" : { "Forename" : "Jeremy", "Surname" : "Dyson" },
"0398" : { "Forename" : "Billy", "Surname" : "Bunter" },
"6714" : { "Forename" : "Harry", "Surname" : "Peterson" },
"9080" : { "Forename" : "Barry", "Surname" : "Mainwaring"}
}
I want to iterate through the objects in peopleobj in order of the surname values, eg to print out the names in surname order. Plain JavaScript or jQuery solutions will work in the context in which this is being deployed.
Thanks in advance for your valuable time.
Interesting question... One plain JavaScript solution is to create an index for your objects in a separate array, based on the 'Surname' property. Something like this1:
var peopleobj = {
"0291" : { "Forename" : "Jeremy", "Surname" : "Dyson" },
"0398" : { "Forename" : "Billy", "Surname" : "Bunter" },
"6714" : { "Forename" : "Harry", "Surname" : "Peterson" },
"9080" : { "Forename" : "Barry", "Surname" : "Mainwaring" }
};
var index = [];
// build the index
for (var x in peopleobj) {
index.push({ 'key': x, 'Surname': peopleobj[x]['Surname'] });
}
// sort the index
index.sort(function (a, b) {
var as = a['Surname'],
bs = b['Surname'];
return as == bs ? 0 : (as > bs ? 1 : -1);
});
Now you would be able to iterate over your index array:
for (var i = 0; i < index.length; i++) {
console.log(peopleobj[index[i]['key']]['Surname']);
}
Result (Tested in Firebug console):
Bunter
Dyson
Mainwaring
Peterson
You may want to wrap this up into some sort of reusable Iterator object, even though it would be difficult to get as terse as Perl:
// Our reusable Iterator class:
function MyIterator (o, key) {
this.index = [];
this.i = 0;
this.o = o;
for (var x in o) {
this.index.push({ 'key': x, 'order': o[x][key] });
}
this.index.sort(function (a, b) {
var as = a['order'],
bs = b['order'];
return as == bs ? 0 : (as > bs ? 1 : -1);
});
this.len = this.index.length;
}
MyIterator.prototype.next = function () {
return this.i < this.len ?
this.o[this.index[this.i++]['key']] :
null;
};
Then use it as follows:
// Our JavaScript object:
var peopleobj = {
"0291" : { "Forename" : "Jeremy", "Surname" : "Dyson" },
"0398" : { "Forename" : "Billy", "Surname" : "Bunter" },
"6714" : { "Forename" : "Harry", "Surname" : "Peterson" },
"9080" : { "Forename" : "Barry", "Surname" : "Mainwaring" }
};
// Build the Iterator object, using the 'Surname' field:
var surnameIter = new MyIterator(peopleobj, 'Surname');
// Iterate:
var i;
while (i = surnameIter.next()) {
console.log(i['Surname'] + ' ' + i['Forename']);
}
Result:
Bunter Billy
Dyson Jeremy
Mainwaring Barry
Peterson Harry
1 You may want to use the hasOwnProperty() method to ensure that the properties belong to your object and are not inherited from Object.prototype:
for (var x in peopleobj) {
if (peopleobj.hasOwnProperty(x)) {
index.push({ 'key': x, 'Surname': peopleobj[x]['Surname'] });
}
}

Categories