Store multiple channel IDs in a JSON file - javascript

I am making a bot using Discord.js and it only needs to track messages in a certain channel, which I currently have this hard-coded for testing purposes.
var { channelID } = require(`./config.json`);
bot.on("message", async (message) => {
const args = message.content.split(/ +/g);
if (message.channel.id === channelID) {
// ...
}
});
I would like for it to store multiple IDs in a JSON file and to have a [p]setchannel command, that would allow me to add one.
I tried this guide, with no luck.

What you probably want to do is store an array of IDs so that you can retrieve them later.
You should have a channelIDs property in your JSON file set to an empty array. Inside your code you can fetch it like this:
const { channelIDs } = require('./config.json') // Now it's an empty array: []
When you want to update this array you should update your local one first, and then you can update the config file: to do that you can use fs.writeFileSync() in combination with JSON.stringify().
const fs = require('fs')
function addChannelID(id) {
channelIDs.push(id) // Push the new ID to the array
let newConfigObj = { // Create the new object...
...require('./config.json'), // ...by taking all the current values...
channelIDs // ...and updating channelIDs
}
// Create the new string for the file so that it's not too difficult to read
let newFileString = JSON.stringify(newConfigObj, null, 2)
fs.writeFileSync('./config.json', newFileString) // Update the file
}
Once you set this function you can add a new ID every time you want, just by calling addChannelID('channel_id').
To check whether the channel the message is coming from should be considered you can use this:
if (channelIDs.includes(message.channel.id)) {
// OK
}

Related

Setting and modifying array and pushing to localStorage creates nested array

I have a function that takes a string from a search field during runtime, and stores it to localstorage. Since we want to store all search strings from the end user to record it, we need to get the current data from localstorage, and add the latest search string.
Here is my code:
const setDatatoLocalStorag = (searchQuery: string) => {
let searchHistory = localStorage.getItem("searchHistory");
let searchQueryArr = [];
if (searchHistory) {
JSON.parse(searchHistory);
searchQueryArr.push(searchQuery, searchHistory);
} else {
searchQueryArr.push(searchQuery);
}
localStorage.setItem("searchHistory", JSON.stringify(searchQueryArr));
}
Lets assume we run the function twice, with the searchQuery "dog" and "cat". This is how it will look like in localstorage:
["cat","[\"dog\"]"]
I believe localstorage will get the item as string "[myData]" which will cause the error. How to properly handle this?
I have tried to follow How to store an array of objects in Local Storage? withous success.
The problem is you aren't assigning JSON.parse(searchHistory); to a variable. I think what you want to do is this:
var searchQueryArr = ['dog'];
localStorage.setItem("searchHistory", JSON.stringify(searchQueryArr));
var searchHistory = JSON.parse(localStorage.getItem("searchHistory") || '[]');
console.log(searchQueryArr, searchHistory);
Note I wasn't able to get this to work with the inline editor, but I did try it on a real server and it worked.
Make a setter/getter pair that hide the encoding/unencoding. Then add a higher-level push that does a get and a set...
// const pretend local storage, keys => strings
const myLocalStorage = {}
function mySetItem(key, value) {
// use the actual local storage setItem() here
myLocalStorage[key] = JSON.stringify(value);
}
function myGetItem(key) {
// use the actual local storage getItem() here
return JSON.parse(myLocalStorage[key]);
}
function myPush(key, value) {
let current = myGetItem(key);
current.push(value)
mySetItem(key, current)
}
// test
const key = 'myKey'
mySetItem(key, []);
myPush(key, { message: 'hello' })
myPush(key, { message: 'dolly' })
console.log(myGetItem(key))

Unable to add object fetched from mongoDB to normal javascript array

I am trying to create an add to cart button which fetches the data from product database using the id of specific product which I selected. I am trying to push the object found using the same Id into a normal javascript array and then to display it using ejs methods. While I was tring I found I am unable to push the data in object form.
Summary:
On 7th line I have declared an array and in that array I want to store some objects which I have fetched frome a db model.
On 15th line I am trying to push the object form into my array so that I could iterate through the objects to display them on my page using ejs. But I am unable to do that.
screenshots:
Here's the final result I'm getting even after trying to push objects in array:
empty array logged
Here are the objects I'm trying to push:
Objects
Code:
app.get("/cart", (req, res) => {
if (req.isAuthenticated()) {
const findcartdata = req.user.username;
userData.findOne({email: findcartdata}, (err, BookId) => {
// console.log(BookId.cartItemId);
const idArray = BookId.cartItemId;
var bookArray = [];
idArray.forEach((data) => {
productData.findOne({_id: data}, (err, foundBookData) =>{
// console.log(foundBookData);
if(err){
console.log(err);
}
else{
bookArray.push(foundBookData);
}
})
});
console.log(bookArray);
// res.render("cart", {
// cartBookArray: BookId.cartItemId
// })
});
} else {
res.redirect("/login");
}
})
In above code i found the user's email using passport authentication user method and using that email I wanted to add the products in a different javascript array (which I am goint to pass to my ejs file of cart and then iterate it on list) using those array of Id which I got from another model called userData. The problem is I am able to find userData of each Id but unable to store them as an array of objects.
Looks like a timing issue, your code completes before the database downloads the objects and pushes them to your array.
This should fix your issue:
// ...
const idArray = BookId.cartItemId;
var bookArray = [];
for (const data of idArray) {
const foundBookData = await productData.findOne({_id: data}).catch(console.error);
if (!foundBookData) continue;
bookArray.push(foundBookData);
}
console.log(bookArray);
// ...
By the way, make sure to make the whole function asynchronous as well, which would be done by changing this line:
userData.findOne({email: findcartdata}, async (err, BookId) => { // ...

Can I treat items found through a Promise.all as a firebase collection?

I am stuck in what I thought was a very simple use case: I have a list of client ids in an array. All I want to do is fetch all those clients and "watch" them (using the .onSnapshot).
To fetch the client objects, it is nice and simple, I simply go through the array and get each client by their id. The code looks something like this:
const accessibleClients = ['client1', 'client2', 'client3']
const clients = await Promise.all(
accessibleClients.map(async clientId => {
return db
.collection('clients')
.doc(clientId)
.get()
})
)
If I just needed the list of clients, it would be fine, but I need to perform the .onSnapshot on it to see changes of the clients I am displaying. Is this possible to do? How can I get around this issue?
I am working with AngularFire so it is a bit different. But i also had the problem that i need to listen to unrelated documents which can not be queried.
I solved this with an object which contains all the snapshot listeners. This allows you to unsubscribe from individual client snapshots or from all snapshot if you do not need it anymore.
const accessibleClients = ['client1', 'client2', 'client3'];
const clientSnapshotObject = {};
const clientDataArray = [];
accessibleClients.forEach(clientId => {
clientSnapshotArray[clientId] = {
db.collection('clients').doc(clientId).onSnapshot(doc => {
const client = clientDataArray.find(client => doc.id === client.clientId);
if (client) {
const index = clientDataArray.findIndex(client => doc.id === client.clientId);
clientDataArray.splice(index, 1 , doc.data())
} else {
clientDataArray.push(doc.data());
}
})
};
})
With the clientIds of the accessibleClients array, i create an object of DocumentSnapshots with the clientId as property key.
The snapshot callback function pushes the specific client data into the clientDataArray. If a snapshot changes the callback function replaces the old data with the new data.
I do not know your exact data model but i hope this code helps with your problem.

Create new object and write to file with fs.writeFile()

There are two things I want to do:
I want to create a new array of objects from an existing object,
And increment the object so each object can have a count id of 1,2,3 etc
My issue is that when I write to the file it writes only 1 random object to the file and the rest don't show. There are so errors and all the objects have the same increment value. Please explain what I am doing wrong. Thanks.
Code:
data.json:
{
"users":[
{
"name":"mike",
"category":[
{
"title":"cook",
}
],
"store":{
"location":"uptown",
"city":"ulis"
},
"account":{
"type":"regular",
"payment":[
"active":false
]
}
}
]
}
index.js:
const appData = ('./data.json')
const fs = require('fs');
let newObject = {}
appData.forEach(function(items){
let x = items
let numincrement = 1++
newObject.name = x.name
newObject.count = numincrement
newObject.categories = x.categories
newObject.store = x.store
newObject.account = x.account
fs.writeFile('./temp.json', JSON.stringify(newObject, null, 2),'utf8' , function(err, data) {
// console.log(data)
if(err) {
console.log(err)
return
} else{
console.log('created')
}
})
})
There are a whole bunch of problems here:
You're just rewriting the same object over and over to the file. fs.writeFile() rewrites the entire file. It does not append to the file. In addition, you cannot append to the JSON format either. So, this code will only every write one object to the file.
To append new JSON data to what's in the existing file, you would have to read in the existing JSON, parse it to convert it to a Javascript array, then add new items onto the array, then convert back to JSON and write out the file again. For more efficient appending, you would need a different data format (perhaps comma delimited lines).
Your loop has all sorts of problems. You're assigning to the same newObject over and over again.
Your numincrement is inside the loop so it will have the same value on every invocation of the loop. You can also just use the index parameter passed to the forEach() callback instead of using your own variable.
If what you're trying to iterate over is the users array in your data, then you may need to be iterating over appData.users, not just appData.
If you really just want to append data to a text file, the JSON is not the easiest format to use. It might be easier to just use comma delimited lines. Then, you can just append new lines to the file. Can't really do that with JSON.
If you're willing to just overwrite the file with the current data, you can do this:
const appData = ('./data.json').users;
const fs = require('fs');
// create an array of custom objects
let newData = appData.map((item, index) => {
return {
name: item.name,
count: index + 1,
categories: item.categoies,
store: item.store,
account: item.account
};
});
// write out that data to a file as JSON (overwriting existing file)
fs.writeFile('./temp.json', JSON.stringify(newData, null, 2),'utf8' , function(err, data) {
if (err) {
console.log(err);
} else {
console.log("data written");
}
});

Cloud Functions for Firebase: how to reference a key in a list that has been just pushed

My question is basically what to do in your cloud function, if you want to reference keys that have been generated when the client called push().
/providerApps/{UID}/ is my path to a list of appointment nodes, so each appointment node is at /providerApps/{UID}/someKey.
I need the "new item in the list", the one that was added with push(), so I thought I could order the keys and simply get the last one, but that does not work:
// (Try to) Listen for new appointments at /providerApps/{pUID}
// and store the appointment at at /clientApps/{cUID}
// cUID is in the new appointment node
exports.storeNewAppForClient = functions.database.ref("/providerApps/{UID}").onWrite(event => {
// Exit when the data is deleted.
if (!event.data.exists()) {
console.log("deletion -> exiting");
return;
}
const pUID = event.params.UID;
const params = event.params;
console.log("params: ", params);
const firstAppVal = event.data.ref.orderByKey().limitToLast(1).val();
// TypeError: event.data.ref.orderByKey(...).limitToLast(...).val is not a function
const date = firstAppVal["dateStr"];
const cUID = firstAppVal["clientUID"];
return event.data.ref.root.child("clientApps").child(cUID).child(date).set(pUID);
});
I guess I could do it on the client side with push().getKey() and allow providers to write into clientApps node, but that seems to be less elegant.
Any ideas how to do this with cloud functions?
As an illustration, my data structure looks like this:
there are provider and their clients who make appointments
Cheers
Change your trigger location to be the newly created appointment instead of the list of appointments. Then you can access the appointment data directly:
exports.storeNewAppForClient = functions.database.ref("/providerApps/{UID}/{pushId}").onWrite(event => {
// Exit when the data is deleted.
if (!event.data.exists()) {
console.log("deletion -> exiting");
return;
}
const pUID = event.params.UID;
const params = event.params;
console.log("params: ", params);
const date = event.data.child('dateStr').val();
const cUID = event.data.child('clientUID').val();
return admin.database().ref('clientApps').child(cUID).child(date).set(pUID);
});
(updated for Frank's comment)

Categories

Resources