Convert Array's into Individual Values in .forEach() - javascript

working on a data transformation project that is taking queries from five different databases, and merge them together. (There are two record sets that are very similar to each other and another set of two that are similar to each other.)
Three of five returned records are fine. The other two (which are similar) are oddly returning certain fields as arrays instead of just single values.
i.e.:
dbRecords = [
{
FirstName: ['john', 'john doe']
}
]
it's definitely due to poor data maintenance, but I want to convert these to single values and I was thinking I could do it something like this.
dbRecords.forEach((item, index, arr) => {
Object.keys(item).forEach(i => {
if(i instanceof Array){
item = item[0];
}
}
});
Would that do the trick?

Would that do the trick?
No, cause item is the object and not the value you want to change, you would have to do:
item[i] = item[i][0];
And additionally, i is always a string and never an Array the check must be:
if(item[i] instanceof Array){
And then you would have to store it back to the db.
PS: i is a bad variable name, why dont you just take key or something similar?

"Three of five returned records are fine. The other two (which are similar) are oddly returning certain fields as arrays instead of just single values."
From that statement, it sounds like you know precisely which two fields are the unexpected arrays. In that case, you shouldn't use a loop, but rather target those fields directly.
So assuming the fields are FirstName and LastName, you can do it like this:
dbRecords = dbRecords.map(({FirstName:[FirstName], LastName:[LastName], ...rest}) =>
({FirstName, LastName, ...rest})
);
This takes advantage of parameter destructuring and "rest sytnax" in object literals to extract the first array member two fields that interest you, as well as the rest of the fields into a separate object, then returns a new object with the extracted values along with the rest of the fields.
Here's a working example:
let dbRecords = [{
FirstName: ['john', 'john doe'],
LastName: ['doe', 'john doe'],
OtherField: "foobar"
}, {
FirstName: ['bob', 'bob smith'],
LastName: ['smith', 'bob smith'],
OtherField: "raboof"
}];
dbRecords = dbRecords.map(({FirstName:[FirstName], LastName:[LastName], ...rest}) =>
({FirstName, LastName, ...rest})
);
console.log(dbRecords);

Related

Remove a property from array of object using reduce API

I am trying to delete a property name from the array of object, it's working properly using filter API,
const users = [
{ name: 'Tyler', age: 28},
{ name: 'Mikenzi', age: 26},
{ name: 'Blaine', age: 30 }
];
const myProp = users.filter(function (props) {
delete props.name;
return true;
});
console.table(myProp);
const myProp2 = users.reduce((people, user) => {
console.log(people);
console.log(user);
delete user.name;
return people;
}, []);
console.log(myProp2);
The same example before I am trying complete using reduce API, However, it's not working as expected.
It's not working because your not pushing to the previous element (you are always returning the empty array). You need to change it to:
const myProp2 = users.reduce((people, user) => {
delete user.name;
people.push(user)
return people;
}, []);
Please note that is not the intended use for reduce though - map is the operation you are looking for:
const myProp2 = users.map(u=> ({age: u.age}));
You actually want to use map for this, because you are selecting a transormation of the data into a new object (similar to Select in SQL or LINQ)
const myProps = users.map(u=> ({age: u.age}))
Also although the filter method worked, this is actually abuse of the filter method. The filter method is supposed to remove elements from the array depending on a condition. Your method worked because you returned true (which removed no elements) but you modified the current value on each iteration.
This is bad practice because you will confuse the next person to look at your code, they will wonder why you used filter as a method to transform the data rather than map.
Also don't use reduce because reduce is an aggregation function intended to perform aggregate functions on objects. Since the number of elements you are returning will be the same, map is better for this.
Reduce would be better suited for if you wanted to find out the average,max,min,median age or the most popular name etc...

JavaScript Arrow Functions - Why are parameters and statements singular versions of array being accessed?

I'm working on learning functional programming, and have been seeing a lot of arrow functions. The arrow functions I'm looking at are accessing arrays and objects and I'm trying to understand why the parameters and statements are singular versions of the array/object name while the actual name is plural? I'm adding a sample to show what I mean:
const users = [
{ name: 'John', age: 34 },
{ name: 'Amy', age: 20 },
{ name: 'camperCat', age: 10 }
];
const names = users.map(user => user.name);
console.log(names); // [ 'John', 'Amy', 'camperCat' ]
You have an array of users, that is to say, a list of users. Every element in the array is a user.
So as others have already pointed out, it's just a convention.
Really smart IDE's will even autogenerate the singular name from the plural when you use code hints/ auto generation.
The map function takes a callback, that user is just one object of the array, it is the same as
for(user of users){}
The map function is what you are really looking at, not arrow functions. This caused me some confusion when I first leared about map(), but really it's all just style.

How to convert JavaScript Array to elements

I have an Array
var fieldsToFetch = ['name', 'class', 'rollNumber'];
I am using this array into NODE-ORM2 query, in simple words, I am saying to ORM that this are the fields I want to fetch.
Person.find({ surname: "Doe" }).limit(3).offset(2).only("name", "class", "rollNumber").run(function (err, people) {
// returning only 'name', 'rollNumber' and 'class' properties
//this is working fine
});
In this code, you can see the .only() function which takes the field names. If I am passing the name here by comma separating then it is working fine but if I do like this
Person.find({ surname: "Doe" }).limit(3).offset(2).only(fieldsToFetch).run(function (err, people) {
// returning only 'name', 'class' and 'rollNumber' properties
// not working
});
I also tried
String(fieldsToFetch ); and fieldsToFetch .toString(); but it converts whole array into a single string. So how can I use this array as a parameter here?
Thankyou.
EDIT
Passing 2 or 3 parameter is not a challenge the main goal is to get all array element as individual elements.
Because you pass an array, but it want separate strings, so if you use ES6 you can pass like .only(...fieldsToFetch).
This is called spread operator. It gets the array, splits it into items and passes them as separate parameters.
Example
function f(a,b,c){
console.log(a);
console.log(b);
console.log(c);
}
var args = [1,2,3];
f(...args);
I pass the array with the spread operator and it splits the array into separate items and assigns to the parameters in direction from left to right.
Try like this..use array.splice() to remove last element from array.Then use ... spread operator:
var fieldsToFetch = ['name', 'class', 'rollNumber'];
fieldsToFetch.splice(2,1);//now array having two elements ['name', 'class']
then
.only(...fieldsToFetch)

Conventions for querystring parameters

When I have a url like this:
http://server/site?firstname=Jack&lastname=Daniels
I understand that in my JavaScript a query for firstname should return "Jack".
But what should the query for firstname return in the following cases:
http://server/site?lastname=Daniels
http://server/site?firstname&lastname=Daniels
http://server/site?firstname=&lastname=Daniels
[Edit] To answer some of the comments: all of the above are legal querystrings, my question is not about how to retrieve the parameters but how to interpret them.
For the record, I parse querystrings with the following regular expression that covers all cases:
/([^?=&;]+)(?:=([^&;]*))?/g
Apparently there's a very popular question on how to retrieve querystring parameters, but the answer is incorrect (or at least not addressing edge cases).
[Update] My choice based on the answers from #Bergi and #zzzzBov:
http://server/site?lastname=Daniels => firstname: undefined
http://server/site?firstname&lastname=Daniels => firstname: true
http://server/site?firstname=&lastname=Daniels => firstname: ""
http://server/site?firstname=Jack&lastname=Daniels => firstname: "Jack"
A side effect is that I had to slightly modify my regex, as with the above rules the = sign needs to be captured:
/([^?=&;]+)(=[^&;]*)?/g
But what should the query for firstname return in the following cases:
http://server/site?lastname=Daniels
http://server/site?firstname&lastname=Daniels
http://server/site?firstname=&lastname=Daniels
Query strings can easily be represented by object notation in JavaScript. Simply set only the keys that are present in the query string on the object.
This means that for ?lastname=Daniels the object produced should be:
{
lastname: 'Daniels'
}
In cases where the key is present, but no value is given (no equals sign), the key should be set with a value of null which represents "no value".
This means that for ?firstname&lastname=Daniels the object produced should be:
{
firstname: null,
lastname: 'Daniels'
}
In cases where the key is present, and the value provided is empty (equals sign), the value is actually the empty string.
This means that for ?firstname=&lastname=Daniels the object produced should be:
{
firstname: '',
lastname: 'Daniels'
}
There is also an often overlooked case of where the same key is used multiple times. In the traditional query-string syntax (not PHP), keys can be used multiple times, as-is, to represent an array.
This means that for ?foo=bar&foo=baz the object produced should be:
{
foo: [
'bar',
'baz'
]
}
<aside>
In PHP land, keys used for arrays are suffixed with []:
`?foo[]=bar&foo[]=baz`
PHP will automatically convert the query-string server side such that:
$_GET['foo'] = array('bar', 'baz')
</aside>
Going back to the original question, what this implies is the following:
?lastname=Daniels has a value of undefined for the firstname key.
?firstname&lastname=Daniels has a value of null for the firstname key.
?firstname=&lastname=Daniels has a value of '' for the firstname key.
For cases where a key is used as a boolean based on its presence, you should be checking whether the object has the key set (and completely ignore the value, as it doesn't matter).
Typically this is done with obj.hasOwnProperty('key'), however as the object is really more of a hash, Object.prototype.hasOwnProperty.call(obj, 'key') is preferrable, which could be abstracted into a has function:
has(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
If you're using underscore.js, then you could use _.has(obj, key)
But what should the query return
That's your decision, what do you need? There are several querystring-evaluating functions of different complexity. Some of them can deal with repeated, nested, bracket-syntax values, others not. Famous ones can be found in How can I get query string values in JavaScript? and its duplicate questions.
However, you asked for conventions:
http://server/site?lastname=Daniels
The result should be something falsy to represent the absence of firstName. You might choose null or undefined.
http://server/site?firstname&lastname=Daniels
This often represents some boolean parameter, so returning true would be legitimate. Yet I'm sure there are libs that completely ignore this format.
http://server/site?firstname=&lastname=Daniels
That's quite obviously the empty string "".

How do I access members of a Javascript object numerically?

Let's say for example, I have the following Javascript object:
var Object = {
Person_A: { name: 'James', age: 40, country: 'Spain' },
Person_B : { name: 'Smith', age: 50, country: 'France' }
}
I want to know how many properties there are in the object Object, and access these properties numerically e.g. through Object[n].
Until now (I don't use Javascript objects much, but I do use JSON as a return format when working with AJAX) I didn't know that Javascript objects don't have a length method and can't be accessed numerically.
I've tried to convert the Javascript object into the same type of JSON that is returned when I make AJAX calls (the JSON is returned as an object with a length method, and is numerically accessible - just read another thread, and maybe I'm wrong about this - double checking now) using JSON.parse(JSON.stringify(Object)) but that simply returns the same exact Object.
So, my question is, what's the most efficient way to take an object like the example, and make it accessible numerically and have a length method.
Any help would be greatly appreciated (and please ask if you need any clarification of my question).
Thanks.
This cannot be done with meaning. The properties of JavaScript objects have no inherent order1.
The length property is a special member of Arrays. (Arrays are just objects that have a specific [[prototype]] and understand how to magically update length -- and have a few other internal rules defined -- that's it!)
Update for comment:
If the index is required, use an Array:
var people = [
{ id: "Person_A", data: { name: 'James', age: 40, country: 'Spain' } },
{ id: "Person_B", data: { name: 'Smith', age: 50, country: 'France' } }
]
people[0].id // "Person_A"
1 JSON "has order" only when serialized as text but implementations, including those that turn it into JavaScript objects, work without access [or assumption] about order; there is no order guarantee for properties per the JSON standard. Just because properties in an object "look" ordered in JSON (or a JS Object Literal), does not imply an order.
If you want to completely replace that object with an array accessible numerically, you could first loop through it to build that new array:
var newArray=new array();
for(i in object){
array.push(i);
}
You can now access that array numerically
function numericIndices(obj) {
var i=0, x;
for( x in obj) {
obj[i] = obj[x];
i++;
}
// next line is OPTIONAL:
obj.length = i;
}
Given an object, this will add the numeric indices to that object. So after running it through that function, the object will have both string keys and numeric keys. If you have the optional line too, you automatically get a length property as well.

Categories