Array list with 2 values and doing it to a top 10 list - node.js

im working on a Discord bot and have a reputation system with fs (npm package) and saving peoples reps in a file and doing the file name as they discord id
now im working on a top 10 command and would need some help here, i currently have this as code:
let users = [];
let reps = [];
fs.readdirSync('./data/reps/').forEach(obj => {
users.push(obj.replace('.json', ''))
let file = fs.readFileSync(`./data/reps/${obj}`)
let data = JSON.parse(file)
reps.push(data.reps)
})
let top = [...users, ...reps]
top.sort((a,b) => {a - b})
console.log(top)
the files form the users are like this:
{
"users": [
"437762415275278337"
],
"reps": 1
}
users are the current users that can't rep the persion anymore and don't need to use it in the command
i wan to get the top 10 of reps so that i can get the user id and how many reps they have, how could i do it with the code above?

You could try this
const topTen = fs.readdirSync('./data/reps/').map(obj => {
const file = fs.readFileSync(`./data/reps/${obj}`);
const data = JSON.parse(file);
return { ...data, name: obj.replace('.json', '') };
}).sort((a, b) => a.reps - b.reps).slice(0, 10);
console.log(topTen);

I would change how you push the data
const users = [];
fs.readdirSync('./data/reps/').forEach(obj => {
let file = fs.readFileSync(`./data/reps/${obj}`)
let data = JSON.parse(file)
reps.push({ reps: data.reps, id: obj.replace(".json", "") });
})
That way when you sort the array the id goes along with
//define this after the fs.readdirSync.forEach method
const top = users.sort((a,b)=> a.reps-b.reps).slice(0,10);
If you want an array of top ids
const topIds = top.map(e => e.id);
If you want a quick string of it:
const str = top.map(e => `${e.id}: ${e.reps}`).join("\n");
Also you should probably just have one or two json files, one would be the array of user id's and their reps and then the other could be of user id's and who they can't rep anymore

Related

Best way to search march in an array of JavaScript Objects?

I'm facing a challenge to match values within an array of JS objects. Let me give you an example,
var dynamicObjectArray = [
{Id: 1422859025, FromTime: "2023-02-12T19:00:00Z", ToTime: "2023-02-12T20:00:00Z"},
{Id: 1422859027, FromTime: "2023-02-12T18:00:00Z", ToTime: "2023-02-12T19:00:00Z"}
]
I need to find all Ids for FromTime or ToTime match with "2023-02-12T19:00:00Z"
Using a database, it can be done easily. But, here, I need to play an array of 100 objects max. Also, data will be dynamic. Can you please suggest me a way to achieve the goal using NodeJS.
You could use the JS Date builtin constructor to compare dates instead of using the string directly.
Filter your matching objects, and map the ids.
You can do something like this.
const dynamicObjectArray = [{
Id: 1422859025,
FromTime: "2023-02-12T19:00:00Z",
ToTime: "2023-02-12T20:00:00Z"
},
{
Id: 1422859027,
FromTime: "2023-02-12T18:00:00Z",
ToTime: "2023-02-12T19:00:00Z"
}
];
const matchTime = new Date("2023-02-12T19:00:00Z").getTime();
const matchIds = dynamicObjectArray.filter(obj => {
const fromTime = new Date(obj.FromTime).getTime();
const toTime = new Date(obj.ToTime).getTime();
return matchTime === fromTime || matchTime === toTime;
}).map(obj => obj.Id);
console.log(matchIds);
If you want a suggestion, you can do something like this:
Create a function that takes as a parameter, the wanted Date
Create a variable containing an array where you will save all those "id's" that match your condition
Create a for loop
Create an if condition, that matches the following condition:
if date exists on "FromTime" or exists on "ToTime", push to your "id's array"
Return your ids array
Here is the code implementation:
function filterObjByDate(TO_MATCH_DATE) {
let ids = [];
for (let i = 0; i < dynamicObjectArray.length; i++) {
if (
dynamicObjectArray[i].FromTime === TO_MATCH_DATE ||
dynamicObjectArray[i].ToTime === TO_MATCH_DATE
) {
ids.push(dynamicObjectArray[i].Id);
}
}
return ids
}
That's it. If you have more question, ask me 😀👍

Svelte Store. Spread syntax is not merging - just adding

I am trying to add some brocolli to my basket in the svelte store I have created. My code adds the brocooli to the basket but then duplicates the baskets and adds a whole new basket to my store. Not sure if the problem is caused by my lack of understanding of javascript or svelte.
Desired result
Basket 1 OrangePineapple Basket 2 BananaApplePlumwalnuthazelnutnutmegbroccoli
ACTUAL RESULT
Basket 1 OrangePineapple Basket 2 BananaApplePlumwalnuthazelnutnutmeg Basket 2 BananaApplePlumwalnuthazelnutnutmegbroccoli
Link to svelte codebox where you can view and run code
https://svelte.dev/repl/80d428000a3f425da798cec3450a59d4?version=3.46.2
if you click the button you see that my basket is duplicating. I am just trying to add the brocooli to the basket.
code below
import { writable } from 'svelte/store';
export const storeBaskets = writable([
{
"name": "Basket 1",
"items": ["Orange", "Pineapple"]
},
{
"name": "Basket 2",
"items": ["Banana", "Apple","Plum","walnut","hazelnut","nutmeg"]
}
])
//Local functions
export const add = (item,basketIndex) => {
storeBaskets.update(val => {
const newItems = [...val[basketIndex].items, item]
const newBasket = {'name':val[basketIndex].name,'items':newItems}
val = [...val,newBasket]
return val
})
val = [...val,newBasket]
With this line you're copying the previous store value and adding the newBasket "on top". That's how the spread operator works with arrays
let arr = [1,2,3]
let n = 4
let arr2 = [...arr, n]
console.log(arr2) // [ 1 , 2 , 3 , 4 ]
I wonder if you might have thought of the different behaviour when spreading an object, where an already existing entry might be overriden if the key already exists
let obj = {key: 'value'}
let key = 'newValue'
let obj2 = {...obj, key}
console.log(obj2) // { key: "newValue" }
To make your code working you could replace the line by val[basketIndex] = newBasket
export const add = (item,basketIndex) => {
storeBaskets.update(val => {
const newItems = [...val[basketIndex].items, item]
const newBasket = {'name':val[basketIndex].name,'items':newItems}
val[basketIndex] = newBasket
return val
})
}
Or, instead of spreading, simply push the new value directly to the according nested array in just one line
export const add = (item,basketIndex) => {
storeBaskets.update(val => {
val[basketIndex].items.push(item)
return val
})
}
You might not need to spread, because it's an array, you'r spreading the existing items of the array and then adding the new basket to it. You can map and replace by basketIndex, like:
export const add = (item,basketIndex) => {
storeBaskets.update(val => {
const newItems = [...val[basketIndex].items, item]
const newBasket = {'name':val[basketIndex].name,'items':newItems}
return val.map((basket, i) => i === basketIndex ? newBasket : basket)
})
}
(Working example)

Firebase NodeJS SDK: Query by value on nested object

I have a collection/table that is structured like this:
{
UsedPromos: {
"userid_1": {
"product_1_1": "promo_1_1",
"product_1_2": "promo_1_2",
...
"product_1_n": "promo_1_n",
},
"userid_2": {
"product_2": "promo_2"
},
...
"userid_m": {
...
}
}
}
How can I query an exact match to some "promo_x_y"? I have tried this so far:
const admin = require("firebase-admin");
admin.initializeApp(...);
const ref = admin.database().ref("/UsedPromos");
ref.orderByValue()
.equalTo("promo_x_y")
.once("child_added")
.then((snapshot) => {
console.log(`{key: ${snapshot.key}, value: ${snapshot.val()}}`);
return snapshot
});
But it didn't return anything.
If you are looking for all products that are part of the promotion promo_x_y, you need to adjust your query one level deeper than what you are currently doing.
Currently you are comparing the values of user_1, user_2, and so on to the value "promo_x_y". You get no results, because no entry /UsedPromos/user_1 = "promo_x_y" exists.
/UsedPromosByUser/{user}/{product} = {promo} (your current structure)
To fix this, you will need to search an individual user's list of products. Using the below snippet will log each product that has a value of "promo_x_y".
const admin = require("firebase-admin");
admin.initializeApp(/* ... */);
const ref = admin.database().ref("/UsedPromos");
const userToSearch = "user_1";
ref.child(userToSearch)
.orderByValue()
.equalTo("promo_x_y")
.once("child_added")
.then((snapshot) => {
// snapshot.val() will always be "promo_x_y", so don't bother logging it.
console.log(`${snapshot.key} uses "promo_x_y"`);
return snapshot;
});
Depending on your use case, it may be better to use a "value" event instead.
const admin = require("firebase-admin");
admin.initializeApp(/* ... */);
const ref = admin.database().ref("/UsedPromos");
const userToSearch = "user_1";
ref.child(userToSearch)
.orderByValue()
.equalTo("promo_x_y")
.once("value")
.then((querySnapshot) => {
const productKeys = [];
// productSnapshot.val() will always be "promo_x_y", so don't bother logging it.
querySnapshot.forEach((productSnapshot) => productKeys.push(productSnapshot.key));
console.log(`The following products have a value of "promo_x_y" for user "${userToSearch}": ${productKeys.join(", "}`);
return productKeys;
});
If you are looking to find all products, across all users, that use "promo_x_y", you should create an index in your database instead of using a query.
/UsedPromosByPromo/{promo}/{user}/{product} = true
OR
/UsedPromosByPromo/{promo}/{product}/{user} = true
Instead of using true in the above structure, you could store a timestamp (time of purchase, time promo expires, etc)

Gmail to Google Spread Sheet (only date, email and subject)

The code I have cobbled together does work, but it imports the wrong things from my email. I only want the date sent, the sender email address and the subject to import into the google sheet.
Can anyone help?
function onOpen() {
const spreadsheet = SpreadsheetApp.getActive();
let menuItems = [
{name: 'Gather emails', functionName: 'gather'},
];
spreadsheet.addMenu('SP LEGALS', menuItems);
}
function gather() {
let messages = getGmail();
let curSheet = SpreadsheetApp.getActive();
messages.forEach(message => {curSheet.appendRow(parseEmail(message))});
}
function getGmail() {
const query = "to:legals#salisburypost.com";
let threads = GmailApp.search(query,0,10);
let messages = [];
threads.forEach(thread => {
messages.push(thread.getMessages()[0].getPlainBody());
label.addToThread(thread);
});
return messages;
}
function parseEmail(message){
let parsed = message.replace(/,/g,'')
.replace(/\n*.+:/g,',')
.replace(/^,/,'')
.replace(/\n/g,'')
.split(',');
let result = [0,1,2,3,4,6].map(index => parsed[index]);
return result;
}
I believe your goal as follows.
You want to retrieve "the date, sender and subject" from the 1st message in the searched threads to the active sheet of Google Spreadsheet.
For this, how about this answer?
Modification points:
In this case, you can retrieve "the date, sender and subject" using the built-in methods for GmailApp.
When the values are put to the Spreadsheet, when appendRow is used in the loop, the process cost will become high.
It seems that label is not declared in your script.
When above points are reflected to your script, it becomes as follows.
Modified script:
In this modification, I modified gather() and getGmail() for achieving your goal.
function gather() {
let messages = getGmail();
if (messages.length > 0) {
let curSheet = SpreadsheetApp.getActiveSheet();
curSheet.getRange(curSheet.getLastRow() + 1, 1, messages.length, messages[0].length).setValues(messages);
}
}
function getGmail() {
const query = "to:legals#salisburypost.com";
let threads = GmailApp.search(query,0,10);
let messages = [];
threads.forEach(thread => {
const m = thread.getMessages()[0];
messages.push([m.getDate(), m.getFrom(), m.getSubject()]);
// label.addToThread(thread);
});
return messages;
}
When no threads are retrieved with "to:legals#salisburypost.com", the values are not put to the Spreadsheet. Please be careful this.
References:
getDate()
getFrom()
getSubject()
setValues(values)

ES6 : Object restructuration for mailchimp api

I want to construct a object base on an array and another object.
The goal is to send to mailchimp api my users interests, for that, I've got :
//Array of skills for one user
const skillsUser1 = ["SKILL1", "SKILL3"]
//List of all my skills match to mailchimp interest group
const skillsMailchimpId = {
'SKILL1': 'list_id_1',
'SKILL2': 'list_id_2',
'SKILL3': 'list_id_3',
}
//Mapping of user skill to all skills
const outputSkills = skillsUser1.map((skill) => skillsMailchimpId[skill]);
console.log(outputSkills);
The problem is after, outputSkill get me an array :
["ID1", "ID3"]
But what the mailchimp api need, and so what I need : :
{ "list_id_1": true,
"list_id_2": false, //or empty
"list_id_3" : true
}
A simple way would be this (see comments in code for explanation):
// Array of skills for one user
const skillsUser1 = ["SKILL1", "SKILL3"]
// List of all my skills match to mailchimp interest group
const skillsMailchimpId = {
'SKILL1': 'list_id_1',
'SKILL2': 'list_id_2',
'SKILL3': 'list_id_3',
}
// Create an output object
const outputSkills = {};
// Use `Object.entries` to transform `skillsMailchimpId` to array
Object.entries(skillsMailchimpId)
// Use `.forEach` to add properties to `outputSkills`
.forEach(keyValuePair => {
const [key, val] = keyValuePair;
outputSkills[val] = skillsUser1.includes(key);
});
console.log(outputSkills);
The basic idea is to loop over skillsMailchimpId instead of skillsUser.
But that is not very dynamic. For your production code, you probably want to refactor it to be more flexible.
// Array of skills for one user
const skillsUser1 = ["SKILL1", "SKILL3"]
// List of all my skills match to mailchimp interest group
const skillsMailchimpId = {
'SKILL1': 'list_id_1',
'SKILL2': 'list_id_2',
'SKILL3': 'list_id_3',
}
// Use `Object.entries` to transform `skillsMailchimpId` to array
const skillsMailchimpIdEntries = Object.entries(skillsMailchimpId);
const parseUserSkills = userSkills => {
// Create an output object
const outputSkills = {};
// Use `.forEach` to add properties to `outputSkills`
skillsMailchimpIdEntries.forEach(([key, val]) => {
outputSkills[val] = userSkills.includes(key);
});
return outputSkills;
}
// Now you can use the function with any user
console.log(parseUserSkills(skillsUser1));

Resources