So I'm currently using csvtojson in order to convert a csv file to, well, json, and my code is returning an array of unnamed objects. However, I want these objects to be named. More specifically, I want to use the values from the first column in order to name the objects.
My CSV file looks like this:
First Name, Restaurant, Food Name, Comment, Price
Andrew, Clucky's Chicken, Chickenator, This sandwich is awesome, $9.99
Michelle, Bytes, Big Burger, Burger was too well done, $12.99
Cam, Candyland, Yummy Gummies, Good price for bulk candy, $1.75
I'm using this code and running it in node:
// require the csvtojson converter class
var Converter = require("csvtojson").Converter;
//create a new converter object
var converter = new Converter({});
//call the fromFile function which takes in the path to the csv file, as well as a callback function
converter.fromFile("./restaurants.csv", function(err,result){
// if an error has occurred, then handle it
if(err){
console.log("An error has occurred");
console.log(err);
}
// create a variable called json and store the result of the conversion
var json = result;
// log our json to verify it has worked
console.log(json);
});
Which returns:
[ { 'First Name': 'Andrew',
'Restaurant': 'Clucky's Chicken',
'Food Name': 'Chickenator',
'Comment': 'This sandwich is awesome',
'Price': '$9.99' },
{ 'First Name': 'Michelle',
'Restaurant': 'Bytes',
'Food Name': 'Big Burger',
'Comment': 'Burger was too well done',
'Price': '$12.99' },
{ 'First Name': 'Cam',
'Restaurant': 'Candyland',
'Food Name': 'Yummy Gummies',
'Comment': 'Good price for bulk candy',
'Price': '$1.75' } ]
But I would like it to return something more along the lines of:
[ Andrew : { 'Restaurant': 'Clucky's Chicken',
'Food Name': 'Chickenator',
'Comment': 'This sandwich is awesome',
'Price': '$9.99' },
Michelle : { 'Restaurant': 'Bytes',
'Food Name': 'Big Burger',
'Comment': 'Burger was too well done',
'Price': '$12.99' },
Cam : { 'Restaurant': 'Candyland',
'Food Name': 'Yummy Gummies',
'Comment': 'Good price for bulk candy',
'Price': '$1.75' } ]
Anybody have any suggestions on how I can do this?
Make a custom function (since you want to convert array into a map).
function arrayToMap(array) {
var map = {};
array.map(
(element) => {
var firstName = element['First Name'];
delete element['First Name'];
map[firstName] = element;
}
);
return map;
}
Create a new array itemArray, then loop for all item in array and push it to itemArray
var itemArray = []
a.map(item => {
firstName = item["First Name"];
delete item["First Name"];
itemArray[firstName] = item;
})
console.log(itemArray); // <<<< you get the result here
Related
I am working on the Google Tag Manager implementation for an eCommerce website.
Unfortunately, we can't hard-code the DataLayers. Therefore I am looking at workarounds. I thought I could implement the datalayers myself using google tag manager and a custom javascript macro.
I am now working on the purchase event.
I successfully scraped the purchase confirmation page and I got three variables, productName, productId and productPrice. Which is all I need for the moment. These three variables come as arrays in the case when multiple products are purchased in the same transaction. So the variables look like the ones shown below.
Now my goal is to format this data in the datalayers format so it can be used in GTM and GA.
See my code below
Thanks for your help!
Jack
//this is what I currently have
var productName = [ 'Product A', 'Product B', 'Product C']
var productId = ['1111', '2222', '3333']
var productPrice = [2.99, 4.95, 6.95]
//this is the format I want to achieve
var products = [{
'name': 'Product A',
'id': '1111',
'price': '2.99'
},
{
'name': 'Product B',
'id': '2222',
'price': '4.95'
},
{
'name': 'Product C',
'id': '3333',
'price': '6.95'
}]
This will work, but I'm not sure about support on all browsers
var column = ['name', 'id', 'price']
var productName = ['Product A', 'Product B', 'Product C']
var productId = ['1111', '2222', '3333']
var productPrice = [2.99, 4.95, 6.95]
var agg = [productName, productId, productPrice];
var row = Object.keys(agg[0])
.map(colNumber => agg.map(rowNumber => rowNumber[colNumber]))
var arr = row.map(function(row) {
return row.reduce(function(result, field, index) {
result[column[index]] = field;
return result;
}, {});
});
var products = arr.reduce(function(acc, cur, i) {
acc[i] = cur;
return acc;
}, {});
console.log(products)
There will be multiple excel files which has the same fields but they might be aligned differently. Such as in first excel file the "price" column might be at the first sequence but at the 2nd file it might be in the 3rd sequence.
So if I were to ask to user to enter sequences under the name of fields (so I'll know the order of fields), could I only convert those fields in the order that I want to JSON with Javascript or Nodejs?
If so, how?
Example:
This is client no. 1's data: stored in this orientation
https://imgur.com/yIgOF8w
This is client no. 2's data: stored in this orientation. 1 extra data that I won't use and different than the first one.
https://imgur.com/lY96c7J
And I want to parse it exactly as how client no. 1 stored. But there are so many varieties that I'll get. So as I explained above, if I were to get the column numbers of certain fields could I get it in the exact format with first client and transform to JSON like that.
You can use the module excel js for this purpose, it has a lot of nice features.
I've updated to allow passing the column order to the readValues function.
For example:
var excel = require('exceljs');
var wb = new excel.Workbook();
var path = require('path');
var client1Path = path.resolve(__dirname, 'client1_data.xlsx');
var client2Path = path.resolve(__dirname, 'client2_data.xlsx');
function readValues(filePath, columnNumbers) {
let columnNames = Object.entries(columnNumbers).reduce((a, [key,value]) => {
a[value] = key;
return a;
}, []);
return wb.xlsx.readFile(filePath).then( () => {
var worksheet = wb.getWorksheet("Sheet1");
var values = [];
worksheet.eachRow((row) => {
let obj = row.values.reduce((o, v, index) => {
if (columnNames[index]) o[columnNames[index]] = v;
return o;
}, {});
values.push(obj);
});
return values;
});
}
async function testReadData() {
try {
let client1Data = await readValues(client1Path, { price: 1, name: 2, country: 3});
console.log('testReadData: Client 1 data: ', client1Data);
let client2Data = await readValues(client2Path, { price: 2, name: 1, country: 4});
console.log('testReadData: Client 2 data: ', client2Data);
} catch (error) {
console.error('testReadData: Error occurred: ', error);
}
}
testReadData();
I'm using the same data as in your examples (now corrected).
e.g.
Client 1 data:
$50 Jack USA
$30 Harold USA
Client 2 data:
Jack $50 Florida USA
Harold $30 California USA
The output will be like:
testReadData: Client 1 data:
[ { price: '$50', name: 'Jack', country: 'USA' },
{ price: '$30', name: 'Harold', country: 'USA' } ]
testReadData: Client 2 data:
[ { name: 'Jack', price: '$50', country: 'USA' },
{ name: 'Harold', price: '$30', country: 'USA' } ]
Is it possible to use a JavaScript object as a type of mini database? I often find myself needing a kind of database structure when I'm coding in JS but it feels like overkill to use an actual database like MySQL (or similar).
As an example, let's say I need to structure this data as a JS object:
Object idea: Stuff to sell
Items to sell: The junk in the garage
Object structure: List all items including item name, item condition, and item value
In order to make this into a JS object I would maybe write:
var stuffToSell = {};
Then my first item would maybe look like:
var stuffToSell = {
item : "Coffee Maker",
condition : "Good",
price : 5
};
Now to me this seems like I'm on the right track, until I come to add another item and I end up having to use the properties item, condition, and price again in the same JS object — which feels wrong? — or is it?? At this point my brain keeps shouting the word "ARRAY!" at me but I just can't see how I can use an array inside the object, or an object inside an array to achieve what I want.
My end goal (in this simplified example) is to be able to then use object-oriented syntax to be able to access certain items and find out specific information about the item such as price, condition etc. For example if I want to know the price of the "coffee maker" I would like to write something like:
stuffToSell["coffee maker"].price
...and then the result above should be 5.
I feel like I'm on the right track but I think I'm missing the array part? Could someone please tell me what I'm missing or maybe what I'm doing completely wrong! And also if it is wrong to have duplicate property names in the same JS object? For example, is it okay to have:
var stuffToSell = {
item : "Coffee Maker",
price : 5,
item : "Mountain Bike",
price : 10,
item : "26 inch TV",
price : 15
};
...it seems wrong because then how does JS know which price goes with which item??
Thanks in advance :)
You're definitely on the right track!
A lot of people will refer to what you're talking about as a hash.
Here's my suggested structure for you:
var store = {
coffee_maker: {
id: 'coffee_maker',
description: "The last coffee maker you'll ever need!",
price: 5,
},
mountain_bike: {
id: 'mountain_bike',
description: 'The fastest mountain bike around!',
price: 10,
},
tv: {
id: 'tv',
description: 'A big 26 inch TV',
price: 15,
},
}
Having a structure like that will let you do this:
store.mountain_bike.price // gives me 10
Need an array instead, say for filtering or looping over?
Object.keys gives you an Array of all the object's keys in the store ['coffee_maker', 'mountain_bike', 'tv']
// Now we just have an array of objects
// [{id: 'coffee_maker', price: 5}, {id: 'mountain_bike', price: 10} ...etc]
var arr = Object.keys(store).map(el => store[el])
Need to just filter for items that are less than 10?
This will give us an array of products less than 10:
// gives us [{id: 'coffee_maker', price: 5}]
var productsUnder10 = arr.filter(el => el.price < 10)
These techniques can be chained:
var productsOver10 = Object.keys(store)
.map(el => store[el])
.filter(el => el.price > 10)
Need to add a product?
store['new_product'] = {
id: 'new_product',
description: 'The Newest Product',
price: 9000,
}
Here's another way, which would be good to start getting used to.
This is a 'safe' way to update the store, read up on immutability in javascript to learn about it
store = Object.assign({}, store, {
'new_product': {
id: 'new_product',
description: 'The Newest Product',
price: 9000,
}
})
...and another way, that you should also read up on and start using:
This is the object spread operator, basically just an easier way to work with immutable structures
store = {
...store,
'new_product': {
id: 'new_product',
description: 'The Newest Product',
price: 9000,
}
}
Resources
JavaScript Arrow Functions
Object and Array Spread Syntax
Immutable Javascript using ES6 and beyond
You can actually use json or create an array of objects.If using a separate file to store the objects, first load the file. Use array filter method to get an new array which matches the filter condition , like you want to get the item with id 1. This will return an array of objects.
var dict = [{
'id': 1,
'name': 'coffee-mug',
'price': 60
},
{
'id': 2,
'name': 'pen',
'price': 2
}
]
function getItemPrice(itemId) {
var getItem = dict.filter(function(item) {
return item.id === itemId
});
return getItem[0].price;
}
console.log(getItemPrice(1))
JSON objects don't support repeated keys, so you need to set unique keys.
Put an id as your key to group your items:
var stuffToSell = {
'1': {
item: "Coffee Maker",
price: 5
},
'2': {
item: "Mountain Bike",
price: 10
}
.
.
.
}
Now you can access the item's price very fast.
Look at this code snippet (Known Ids)
var stuffToSell = {
'1': {
item: "Coffee Maker",
price: 5
},
'2': {
item: "Mountain Bike",
price: 10
},
'3': {
item: "26 inch TV",
price: 15
}
};
let getPrice = (id) => stuffToSell[id].price;
console.log(getPrice('1'));
See? the access to your items it's fast and your code follows a readable structure.
Look at this code snippet (Item's name as key)
var stuffToSell = {
'Coffee Maker': {
price: 5
},
'Mountain Bike': {
price: 10
},
'26 inch TV': {
price: 15
}
};
let getPrice = (id) => stuffToSell[id].price;
console.log(getPrice('Coffee Maker'));
Look at this code snippet (Item's name: price)
var stuffToSell = {
'Coffee Maker': 5,
'Mountain Bike': 10,
'26 inch TV': 15
};
let getPrice = (id) => stuffToSell[id];
console.log(getPrice('Coffee Maker'));
I want to get only the AID from the solution now i am getting. I tried rows[0] but was not successful.
Code:
console.log('The solution is: ', rows);
Output:
The solution is:
[ { AID: 6520,
DID: 113071,
TITLE: 'First Knight',
DATE: '7/7/1995',
SCORE: 89 } ]
Use rows[0]["AID"] to access the AID property.
Let's understand your overall data structure here:
var rows = [
{
AID: 6520,
DID: 113071,
TITLE: 'First Knight',
DATE: '7/7/1995',
SCORE: 89
}
];
The variable rows is an array of objects. Thus rows[n] gets you a specified object in that array and therefore rows[0] is the first object in the array which would be:
{
AID: 6520,
DID: 113071,
TITLE: 'First Knight',
DATE: '7/7/1995',
SCORE: 89
}
So, now you want to access the AID property in that object so you can just do:
rows[0].AID
And, here's a working snippet demo:
var rows = [
{
AID: 6520,
DID: 113071,
TITLE: 'First Knight',
DATE: '7/7/1995',
SCORE: 89
}
];
document.write(rows[0].AID);
Here's the data. What I want to do is inject all this data into one variable that contains all the categories and all the books belonging to those categories:
var categories = [
// ...
{
"_id" : "5436b12b456f61180f815c06",
"name" : "Horror"
},
{
"_id" : "5436b43f18bbc8a8073e786e",
"name" : "Action"
}
// ...
];
var books = [
// ...
{
"_id" : "5436b43f18bbc8a8073e786d",
"title" : "The Bourne Legacy",
"category" : "5436b43f18bbc8a8073e786e"
},
{
"_id" : "5436b5c9de9884e010d5ef24",
"title" : "Digital Fortress",
"category" : "5436b50dc6faf3d41071a669"
}
// ...
];
And this is a mockup of how I'd like the data to look like after filtering:
categories_titles = [
{
categoryName: 'Category One',
categoryTitles: [
{title: 'Book 1'},
{title: 'Book 2'},
// ...
]
},
{
categoryName: 'Category Two',
categoryTitles: [
{title: 'Book 3'},
{title: 'Book 4'},
// ...
]
}
];
And this is how I'm trying to solve the problem:
categories_titles= [];
for (var category in categories) {
for (var book in books) {
if (books[book].category == categories[category]._id) {
categories_titles.push(
{
name: categories[category].name,
titles: [
{title: books[book].title}
]
}
);
}
}
}
This method works only partially; all the categories are being listed but some are being repeated, and some titles are missing or otherwise not where they're supposed to be.
Also, accessing items, something like: categories_titles[0].titles[0].title is quite a monstrosity and I have a feeling that this could be solved more elegantly.
Please advise.
There is indeed a much better way to do this. I'm going to rearrange your data structure. The filter to go from my data structure to yours is a linear time algorithm, though I don't see why you'd want to. But if you must, the translation is linear time.
result = {};
for (var category in categories) {
result[category._id] = {name : category.name, books: []};
}
for (var book in books) {
//Probably also want some safety logic for if result[book.category] is undefined...
addBook(result[book.category].books, book); //you already know how to add your book info, so I won't duplicate that logic.
}
Afterwards you can either return result, or do logic to change result into your mocked up data structure. But creating this preliminary structure will save you computation time, because dictionary accesses are MUCH faster than iterating over your arrays multiple times.
If b = number of books and c = number of categories.
Complexity Your algorithm: O(b * c)
Complexity My algorithm: O(b + c)
Complexity My algorithm with translation to your data structure O(2 * (b + c)) though the memory complexity goes up. A good tradeoff for this problem, in my opinion. O(b*c) is not very good.