Add JSON values from two different files into a single file - javascript

I just need to merge two files with the same list, but with different values on each file. Preferably in JavaScript
For example:
File 1
{"list1":{"a":1,"b":2}
{"list2":{"c":3,"d":4}
File 2
{"list1":{"a":5,"b":6}
{"list2":{"c":7,"d":8}
The desired result is
{"list1":{"a":6,"b":8}
{"list2":{"c":10,"d":12}
Sorry for the noob question, but the person who sent me the files should have done this themselves, but are currently unavailable. The files are too big to do by hand.

This is not very flexible code, but it would be far more work, to make something more dynamic. You would have to parse the objects recursevely and check if the property is an object and then jump deeper. Until ou find the values.
And please be aware that I'm not making any type checking whatsoever. If the data contains faulty data it is not cought properly. Also this code requires this exact structure. If your object contains other properties it might crash too.
// your data
const f1l1 = '{"list1":{"a":1,"b":2}}';
const f1l2 = '{"list2":{"c":3,"d":4}}';
const f2l1 = '{"list1":{"a":5,"b":6}}';
const f2l2 = '{"list2":{"c":7,"d":8}}';
var result1= JSON.parse(f1l1);
var result2= JSON.parse(f1l2);
//the names of the list as they appear in your real data *must* be the first object
const nameList1 = Object.keys(result1)[0];
const nameList2 = Object.keys(result2)[0];
//remove the list name
result1=result1[nameList1];
result2= result2[nameList2];
//get data from other file nd remove list name
const file2List1= JSON.parse(f2l1)[nameList1];
const file2List2= JSON.parse(f2l2)[nameList2];
// go through all items and sum them if the value is already in the list, else put it in for list1
for (var prop in file2List1) {
if (Object.prototype.hasOwnProperty.call(file2List1, prop)) {
if(Object.prototype.hasOwnProperty.call(result1, prop)){
result1[prop] = result1[prop] + file2List1[prop];
}else{
result1[prop] = file2List1[prop];
}
}
}
// and now for list2
for (var prop in file2List2) {
if (Object.prototype.hasOwnProperty.call(file2List2, prop)) {
if(Object.prototype.hasOwnProperty.call(result2, prop)){
result2[prop] = result2[prop] + file2List2[prop];
}else{
result2[prop] = file2List2[prop];
}
}
}
//put names of lists back in.
result1 = {[nameList1]:result1};
result2 = {[nameList2]:result2};
//check results:
console.log("input data:");
console.log(JSON.parse(f1l1));
console.log(JSON.parse(f1l2));
console.log(JSON.parse(f2l1));
console.log(JSON.parse(f2l2));
console.log("output data:");
console.log(result1);
console.log(result2);

You can try this out
newList = list1.concat(list2);

Related

Use array of invoice numbers to create invoice objects within which each invoice number from the initial array serves as id property

Building a script in google apps script.
I get values from an invoice data sheet with multiple lines per invoice so as to account for line items.
My progress so far has been to extract individual invoice numbers from the column (each invoice number occurs as many line items the individual invoice has).
The array todaysInvoices looks like this: [35033817, 35033818, 35033819, 35033820, 35033821]
Now, I need a way to create an object for each of these invoice numbers that has different properties (such as invoiceDate and customerName etc.). The initial invoice number as in the array should thereby be assigned as 'id' property to the new invoice object.
I need help to use objects in javascript.
If you require additional information, please let me know.
Below is a screenshot of a simplified version of my order sheet:
This is a clipping of my order sheet. Before and after the shown columns there are many more with more details but the hierarchies of information are already in the image
Below is the code I have so far:
const orderSheet = SpreadsheetApp.openById('SPREADSHEETID').getSheetByName('SHEETNAME');
const invoiceTemplate = DriveApp.getFileById('DOCUMENTID');
const tempFolder = DriveApp.getFolderById('FOLDERID');
const invoiceData = orderSheet.getRange(4,7, orderSheet.getLastRow() - 1, 57).getDisplayValues().filter(function (rows){ return rows[0] === 'INVOICED'});
const invDataRepo = SpreadsheetApp.openById('SPREADSHEETID2');
var timestamp = new Date();
function printBulkInvoices() {
logLineItems ();
var todaysInvoices = uniqueInvIDs ();
todaysInvoices.sort();
todaysInvoices.map(String);
//fetchInvData (todaysInvoices);
Logger.log (todaysInvoices)
}
function fetchInvData (invoiceIDs) {
let invoices = {
}
Logger.log(invoices)
invoiceIDs.forEach
}
function fetchLineItems (invoiceDataArray) {
}
// send array of todays unique invoice numbers (later all inv data?) to invdata sheet and log them
function logTodaysInvoices (invIDArr){
invIDArr.forEach
invDataRepo.getSheetByName('invdata').getRange(invDataRepo.getSheetByName('invdata').getLastRow()+1,1,invIDArr.length,1).setValue(invIDArr);
}
// return an array of unique invoice ids from todays invoice data
function uniqueInvIDs (){
let singleArray = invoiceData.map(row => row[5]);
let unique = [...new Set(singleArray)];
return unique;
}
//log incoicedata to invdatarepo-sheet 'lineitems'
function logLineItems (){
invDataRepo.getSheetByName('lineitems').getRange(invDataRepo.getSheetByName('lineitems').getLastRow()+1,2,invoiceData.length,invoiceData[0].length).setValues(invoiceData);
}
It's hard to say exactly what you need since we cannot see your Invoice Data Sheet.
But here's something that might give you a start:
let iobj = {idA:[]};
[35033817, 35033818, 35033819, 35033820, 35033821].forEach((id => {
if(!iobj.hasOwnProperty(id)) {
iobj[id]={date: invoiceDate, name: customName, items:[]};
iobj.idA.push(id);//I find it handy to have an array of object properties to loop through when I wish to reorganize the data after it's all collected
} else {
iobj[id].items.push({item info properties});//I am guessing here that you may wish to addition additional information about the items which are on the current invoice
}
});
Javascript Object
To follow up from your question:
Your loop to collect object data would start to look something like this:
function getInvoiceData() {
const ss = SpreadsheetApp.getActive();
const ish = ss.getSheetByName('Invoice Data');
const isr = 2;
const hA = ish.getRange(1, 1, 1, ish.getLastColumn()).getValues()[0];
let idx = {};//object return head index into row array based on header title which in this case I assume invoice number is labeled 'Invoicenumber'
hA.forEach((h, i) => {idx[h] = i});
const vs = ish.getRange(isr, 1, ish.getLastRow() - isr + 1, ish.getLastColumn()).getValues();
let iobj = { idA: [] };
vs.forEach(r => {
if (!iobj.hasOwnProperty(r[idx['invoicenumber']])) {
iobj[r[idx['invoicenumber']]] = { date: r[idx['invoicedate']], name: r[idx['customername']], items: [] };
iobj.idA.push(r[idx['invoicenumber']]);
} else {
iobj[r[idx['invoicenumber']]].items.push({ iteminfoproperties:'' });
}
});
}

Map key of object with array of object value

Suppose I have an array of object as:
const bookDetails = [{"author":"john","email":"john#gmail.com","readingTime":"121"},
{"author":"romero","email":"romero#gmail.com","readingTime":908},
{"author":"romero","email":"alpha#gmail.com","readingTime":1212},
{"author":"buck","email":"buck#gmail.com","readingTime":1902},
{"author":"buck","email":"bujor#gmail.com","readingTime":12125},
{"author":"romero","email":"romero#gmail.com","readingTime":500},
{"author":"john","email":"john#gmail.com","readingTime":10},
{"author":"legend","email":"legend#gmail.com","readingTime":12}
{"author":"john","email":"john#gmail.com","readingTime":1890}]
I have an object as:
const toMatch = {"romero#gmail.com":1212,"john#gmail.com":1248,"bujor#gmail.com":909}
I want to replace emailId with corresponding author.
So my expected O/P should be: {"romero":1212,"john":1248,"buck":909}
If anyone needs any further information please let me know.
You can generate a new object by iterating over bookDetails and look up the values from toMatch
Like this
const bookDetails=[{"author":"john","email":"john#gmail.com","readingTime":"121"},{"author":"romero","email":"romero#gmail.com","readingTime":908},{"author":"romero","email":"alpha#gmail.com","readingTime":1212},{"author":"buck","email":"buck#gmail.com","readingTime":1902},{"author":"buck","email":"bujor#gmail.com","readingTime":12125},{"author":"romero","email":"romero#gmail.com","readingTime":500},{"author":"john","email":"john#gmail.com","readingTime":10},{"author":"legend","email":"legend#gmail.com","readingTime":12},{"author":"john","email":"john#gmail.com","readingTime":1890}]
const toMatch = {"romero#gmail.com":1212,"john#gmail.com":1248,"bujor#gmail.com":909}
const result = {};
for (const detail of bookDetails) {
const {email, author} = detail;
if (email in toMatch) {
result[author] = toMatch[email];
}
}
console.log(result);
Ah, you want to matching names from emails based on the array of objects. Is that right? If so..
const bookDetails=[{"author":"john","email":"john#gmail.com","readingTime":"121"},{"author":"romero","email":"romero#gmail.com","readingTime":908},{"author":"romero","email":"alpha#gmail.com","readingTime":1212},{"author":"buck","email":"buck#gmail.com","readingTime":1902},{"author":"buck","email":"bujor#gmail.com","readingTime":12125},{"author":"romero","email":"romero#gmail.com","readingTime":500},{"author":"john","email":"john#gmail.com","readingTime":10},{"author":"legend","email":"legend#gmail.com","readingTime":12},{"author":"john","email":"john#gmail.com","readingTime":1890}]
function namesMap(object,list){
//to save complexity(assuming the array is huge), I'd just loop through the list once to get the data I need
var obj={} //relates emails to names
list.forEach(item=>{
obj[item.email]=item.author
})
var toReturn={}
Object.keys(object).forEach(email=>{
toReturn[obj[email]]=object[email] //email to name conversion
})
return toReturn
}
//example usage
const toMatch = {"romero#gmail.com":1212,"john#gmail.com":1248,"bujor#gmail.com":909}
console.log(namesMap(toMatch,bookDetails))
There you go, I'm 100% you can do this easier, but this is the fastest response that came to my mind:
function changeData(bookDetails){
let returnableObject = {};
bookDetails.forEach(book => {
returnableObject[book.author] = book.readingTime
})
return returnableObject;
}
*EDIT -> This would work if your Author name IS UNIQUE if the author name is not unique you should change the name or maybe use an array of objects, not an object with multiple values...
*EDIT 2 -> I think I didnt understand your question.

Order new posts first in firebase

I am retrieving data from firebase and storing it into list items. But I want to reverse the order, which will bring new posts at the top. What should I add to make it work that way?
JsFiddle of my code
This is my function for retrieving the data
const dbRef = firebase.database().ref();
const usersRef = dbRef.child('users');
readUserData();
// READ
function readUserData() {
const userListUI = document.getElementById("user-list");
usersRef.on("value", snap => {
userListUI.innerHTML = ""
snap.forEach(childSnap => {
let key = childSnap.key,
value = childSnap.val()
let $li = document.createElement("li");
// edit icon
let editIconUI = document.createElement("span");
editIconUI.class = "edit-user";
editIconUI.innerHTML = " ✎";
editIconUI.setAttribute("userid", key);
editIconUI.addEventListener("click", editButtonClicked)
// delete icon
let deleteIconUI = document.createElement("span");
deleteIconUI.class = "delete-user";
deleteIconUI.innerHTML = " ☓";
deleteIconUI.setAttribute("userid", key);
deleteIconUI.addEventListener("click", deleteButtonClicked)
$li.innerHTML = value.name;
$li.append(editIconUI);
$li.append(deleteIconUI);
$li.setAttribute("user-key", key);
$li.addEventListener("click", userClicked)
userListUI.append($li);
});
})
}
While Firebase offers operations to determine the order in which nodes are returned, there is no operation to return them in descending order.
There are two common workarounds for this:
Include an inverted timestamp in the data, and order on that.
Reverse the results client-side.
In your case, it is simplest to do the latter: as you can just prepend each message to the list instead of appending it:
userListUI.prepend($li);
There are three methods to sort data with the Realtime database.
orderByChild() will order results by the value of a specified child key or nested child path.
orderByKey() will order results by child keys.
orderByValue() will order results by child values.
Find out more here

Large json, store two fields in an array

I have a large json file that needs to have to "fields" merged in to an array in order to store to firestore.
Here a screenshot to show what I mean. What i have:
What I need:
As you can see GRP1D and GRP2D where merged in to an array. The json has 15000 entries so doing it manually is not an option
You can write a script using NodeJS to edit this huge file similar to the following:
const largeJson = require('./largeJson.json');
// I am assuming here that the large JSON file is an array of objects
const mergedJson = largeJson.map(obj => {
const objEditted = { ...obj, GRP1D: [ obj.GRP1D, obj.GRP2D ] };
delete objEditted.GRP2D;
return objEditted;
});
// mergedJson now holds an array of objects which merge the fields
// GRP1D and GRP2D as you described in the example
Here is small code snippet using the spread operator
const your_data = require("./your_data/ file/path");
const prepare_func = (your_data)=>{
let temp = {...your_data,"GRP1D":[your_data["GRP1D"],your_data["GRP2D"]]};
return temp;
}
let new_data = prepare_func(your_data);

Parse.com issues while querying array of pointers, .include not getting nested pointer data in cloud code

I am having trouble getting data from the nested pointers in my array of pointers from a query. I have an array of pointers like so: [{"__type":"Pointer","className":"QuizData","objectId":"rmwJrV55c7"},{"__type":"Pointer","className":"QuizData","objectId":"2132q8i9np”}, etc…]
That QuizData class also has a column named “ad” which is a Pointer to the “Ads” class. I can get the QuizData in a query using the following include statements on my query like so:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include("quizAdArr”);
__quizAdQueueQuery.include(["quizAdArr.QuizData"]);
BUT Neither of these or both combined don’t work as when I try to get column data from the ad it’s always undefined:
__quizAdQueueQuery.include(["quizAdArr.QuizData.ad"]);
__quizAdQueueQuery.include(["quizAdArr.QuizData.Ads"]);
This is my return from that query, where the column data "mediaType" that I am trying to access is always undefined:
return __quizAdQueueQuery.first().then(function(__resultsObj)
{
__quizQueueObj = __resultsObj;
__userQuizQueueArr = __quizQueueObj.get("quizAdArr");
var __quiz;
var __ad;
var __seenAd;
var __lengthInt = __userQuizQueueArr.length;
var __mediaTypeStr = __request.params.mediaType;
var __matchedQuizzesArr = [];
for (var __i = 1; __i < __lengthInt; __i++)
{
__quiz = __userQuizQueueArr[__i];
// console.log('__quiz.get("name") = '+__quiz.get("name"));
__ad = __quiz.get("ad");
// console.log("__ad.id = "+__ad.id);
//THE MEDIA TYPE IS ALWAYS RETURNING UNDEFINED HERE!!!
console.log('__ad.get("mediaType") = '+__ad.get("mediaType")+', __mediaTypeStr = '+__mediaTypeStr);
if (__ad.get("mediaType") == __mediaTypeStr)
{
//put all matches in array to be sorted
__matchedQuizzesArr.push(__userQuizQueueArr[__i]);
console.log("__matchedQuizzesArr.length = "+__matchedQuizzesArr.length);
}
}
return __matchedQuizzesArr;
});
Thanks for any help you can give! I also posted this as a bug in the Parse/Facebook issue reporter but was redirected here, so if this is a bug I can reopen it: https://developers.facebook.com/bugs/923988310993165/
EDIT Here is the updated, working query with nested includes for clarity:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include('quizAdArr');
__quizAdQueueQuery.include('quizAdArr.ad');
This should work (you only need to list the column names):
query.include('quizAdArr.ad');
Here's why:
You're querying QuizAdQueue so you don't need to list that
The QuizAdQueue class has an array in quizAdArr so you include it: query.include('quizAdArr');
Each quizAdArr element is a QuizData with an ad so you include it: query.include('quizAdArr.ad');
The issue was that you were including QuizData which is the name of a class and not a column name

Categories