Merge json array object to itself - node.js

would like to ask, how to merge in nodejs
[ {"id":"1234","pick1":"Heart","isHit1":false},{"id":"2345","pick1":"Spade","isHit1":false},{"id":"1234","pick2":"Diamond","isHit2":false},{"id":"2345","pick2":"Clubs","isHit2":false} ]
To this
[{"id":"1234","pick1":"Heart","isHit1":false,"pick2":"Diamond","isHit2":false}, {"id":"2345","pick1":"Spade","isHit1":false,"pick2":"Clubs","isHit2":false}]
What i've tried is, doing a for loop, but, it takes a while, cause i'm processing around 100 data.
Update:
Already found a shorthand for this, thank you!
Solution:
let result = json1.map(obj => {
let data = json1.find(item => item.id === obj.id);
return {...obj, ...data}
});

Processing wise this one is fastest solution, it just loops n times [we can say O(n) complexity]:
let dict = {};
for (let i = 0; i < a.length; i++) {
dict[a[i].id] = {...dict[a[i].id], ...a[i]};
}
let output = [];
for (key of Object.keys(dict)) {
output.push(dict[key]);
}
console.log(output);

Related

What is the best way in nodejs to compare two different array of objects based on one or more attributes/fields? The fields name can be different

let obj1 = [{field1:11, field2:12, field3:13}, {field1:21, field2:22, field3:23}, {field1:31, field2:32, field3:33}, {field1:41, field2:42, field3:43}];
let obj2 = [{attribute1:21, attribute2:22}, {attribute1:31, attribute2:32}, {attribute1:11, attribute2:12}];
let output = [];
obj1.map(o1 => {
for (let i=0;i<obj2.length;i++) {
if (o1.field1 === obj2[i].attribute1) {
output.push(Object.assign(obj2[i], o1));
obj2.splice(i,1);
break;
}
}
});
console.log(output); //*[{attribute1:11,attribute2:12,field1:11,field2:12,field3:13},{attribute1:21,attribute2:22,field1:21,field2:22,field3:23},{attribute1:31,attribute2:32,field1:31,field2:32,field3:33}]*
The above code compares two different objects with its fields.
Here I am using 2 loops.
So my question is, do we have any better approach to achieve the same? Without two loops or using any package or the best way
You can use find to find the first element where the statement is true instead of looping and manually checking if the statement is true or false. Sadly find is also an iterative method but I don't see any other way to improve this. I am using filter to remove the elements that don't fulfil the condition o2.attribute1 === o1.field1.
let obj1 = [{field1:11, field2:12, field3:13}, {field1:21, field2:22, field3:23}, {field1:31, field2:32, field3:33}, {field1:41, field2:42, field3:43}];
let obj2 = [{attribute1:21, attribute2:22}, {attribute1:31, attribute2:32}, {attribute1:11, attribute2:12}];
const output = obj1.map(o1 => {
let obj2Value = obj2.find(o2 => o2.attribute1 === o1.field1);
return obj2Value ? Object.assign(obj2Value, o1) : null;
}).filter(o => o !== null);
console.log(output);
Alternatively you can use forEach to do this:
let obj1 = [{field1:11, field2:12, field3:13}, {field1:21, field2:22, field3:23}, {field1:31, field2:32, field3:33}, {field1:41, field2:42, field3:43}];
let obj2 = [{attribute1:21, attribute2:22}, {attribute1:31, attribute2:32}, {attribute1:11, attribute2:12}];
let output = [];
obj1.forEach(o1 => {
let obj2Value = obj2.find(o2 => o2.attribute1 === o1.field1);
obj2Value ? output.push(Object.assign(obj2Value, o1)) : '';
});
console.log(output);
There are several approaches to achieve this. Also remember map already returns a new array so no need to use push inside, just return. Check this for better understanding:
https://stackoverflow.com/questions/34426458/javascript-difference-between-foreach-and-map#:~:text=forEach%20%E2%80%9Cexecutes%20a%20provided%20function,every%20element%20in%20this%20array.%E2%80%9D .

How to add Numbers In Arrays format if we have a word in 3 files using nodejs

I want to ask a question, what is it, I have three files, if there is a Word COMMON in those files then it should be printed like this [1,2 3], otherwise, if there is a word in 1 and 2 then it should be printed like this [1 2] , I Tried to PUSH ARRAY but it's not happening
Here Is My Code:
let Page1data = filtered.map((val) => {
let data = {};
if (Page1.includes(val)) {
data[val] = ["1"];
}
if (Page2.includes(val)) {
data[val] = ["2"];
}
if (Page3.includes(val)) {
data[val] = ["3"];
}
return data;
});
console.log(Page1data);
If I get it right, the problem is with your declaration.
.push() is for arrays not for objects. You have declared your data variable as an object.
You should use:
let data = [];
instead of
let data = {};
So it's going to look like this:
let data = [];
if (Page1.includes(val)) {
data.push("1");
}
etc...

NodeJS TypeError: Cannot read properties of undefined (reading '0')

I get the enemyCards from the frontend and it is an array, with 990 x 7 poker cards.
The sortCardOrder function just take the cards in order so i can search in my datas.
This is my NodeJS code:
import fs from 'fs';
import G from 'generatorics';
export default function findEnemyStrongest(enemyCards) {
let eCombination = enemyCards.enemyCards;
let result = [];
for(const comb of eCombination){
result.push(findStrongest(comb));
}
console.log(result);
}
function createCombinations(enemyC){
let combine = enemyC;
let onlyName = [];
let allCombinations = [];
for (let card of combine){
onlyName.push(card.name);
}
for (let comb of G.combination(onlyName, 5)){
allCombinations.push(comb.slice());
}
return allCombinations;
}
function findStrongest(combi){
let rawdata = fs.readFileSync('data.json');
let strenghtOrder = JSON.parse(rawdata);
let combinations = createCombinations(combi);
let combinationsName = [];
let ordered = "";
let result = [];
for(let combination of combinations){
let nameString = "";
let colors = {'C': 0, 'S': 0, 'H':0, 'D':0};
for(let card of combination){
nameString += card[0];
colors[card[1]]+=1
}
ordered = sortCardOrder(nameString, colors);
combinationsName.push(ordered);
console.log(combinationsName)
result.push(strenghtOrder.cardStrenght[ordered]);
}
return Math.min(...result);
}
function sortCardOrder(string, colors){
}
Can anyone know what is the problem?
We can infer this line is causing the error:
nameString += card[0];
It is requesting the 0 property of the card variable, but card is undefined. Card gets its value from combination. Print out combination to see if it has undefined values.
...
for(let combination of combinations){
console.log(combination)
...
Combination gets it value from combinations, which comes from comb. Print out the values of comb.
...
for (let comb of G.combination(onlyName, 5)){
console.log(comb)
...
Keep going backwards until you find the source of the 'undefined' value. Without seeing the original source data (from G), stepping through the code is the only way to find the error source.

Write to json file in increments of 50

I am currently looping through a json object with the purpose of writing certain key value pairs to a new json file. I can write all the elements in the newVideos array to a new file. However, I need to get the first 50 and write it to a file, then the next 50 and so on... Can anyone point me in the right direction?
async function GetVideos(videoData) {
var videos = videoData.videos;
var newVideos = [];
for (var i = 0; i < videos.length; i++) {
var o = videos[i];
newVideos[i] = {
ID: o.ID,
Videos: o.Videos
};
}
}

Am I paginating through a huge Firebase collection the right way?

I am trying to find a way to iterate all objects from a large collection of data in Firebase Database.
My best attempt follows but I found it odd for several reasons:
startAt() values are always inclusive. So after fetching 100 elements, I had to use my last fetched key as an argument to startAt which results in the last item being fetched again
DataSnapshot's forEach method doesn't allow a callback with an index count as you would think it would based on JS's standards so I had to create a manual index - not sure it will work in every case as i'm not sure if forEach works perfectly synchronously
Here is my code, given the assumption my collection is located at users.
const mapAllTripsPaginated = function (database, childSnapshotCallback, start = '', limit = 100, totalNb = 0) {
return database.ref('/users').orderByKey().startAt(start).limitToFirst(limit).once('value').then((snapshot) => {
let childrenPromises = []
let lastChildKey = null
let idx = 0
snapshot.forEach((childSnapshot) => {
lastChildKey = childSnapshot.key
if (start !== '' && idx === 0) {
// console.log(`Skipping ${childSnapshot.key} as 1st element of page`)
} else {
childrenPromises.push(childSnapshotCallback(childSnapshot))
}
idx = idx + 1
})
return Promise.all(childrenPromises)
.then((result) => {
let newTotal = totalNb + result.length
if (snapshot.numChildren() === limit) {
console.log(`Paginating from ${lastChildKey}`)
return mapAllTripsPaginated(database, childSnapshotCallback, start = lastChildKey, limit = limit, totalNb = newTotal)
} else {
// Done paginating
return newTotal
}
})
})
}
Any idea on how I could make this method more elegant?
Firebase queries are inclusive both for their start and end conditions. You will indeed have to deduplicate the overlapping item on the client.
Firebase's Snapshot.forEach() is a synchronous operation.
I'd normally deduplicate based on already having the key of the item. That will also remove the need for the idx counter.
snapshot.forEach((childSnapshot) => {
if (lastChildKey !== childSnapshot.key) {
childrenPromises.push(childSnapshotCallback(childSnapshot))
}
lastChildKey = childSnapshot.key
})

Resources