I'm trying to make an array of sets to make something like this
{
'user1': ["value#1", "value#2",..."value#N"],
'user2': ["value#2",..."value#N"],
'userN': [..."value#N"]
}
and then remove the value#x after 5 seconds (for example).
here is my code:
var myset = new Set();
var ran = myset[USERID] = commandNumber;
//i'm trying to make "if myset contains userNumber AND commandName" return,
//if its not, run someFunction() and continue
if (myset.has(ran)) return;
someFunction();
myset.add(ran);
setTimeout(() => {
myset.delete(ran);
}, 5000);
instead of getting output like the first code, i get this output instead
Set { 'command1', 'command2',
'USER1': 'command3',
'USER2': 'command4'
'USERN': 'commandN'
}
Feel free to comment if you have a question, so sorry if my question is hard to understand
A Set for this purpose is not necessary but I did a small POC that could help you to implement the solution you need:
'use strict';
const mySet = new Set();
const mySetMetadata = {};
const removeFromSet = (userKey, commandName) => {
const commands = mySetMetadata[userKey] || [];
if (commands.includes(commandName)) {
mySetMetadata[userKey] = commands.filter(c => c !== commandName);
if (mySetMetadata[userKey].length === 0) {
mySet.delete(userKey);
mySetMetadata[userKey] = undefined;
}
}
};
/**
* Add relation between an userKey and a command
* #param {String} userKey
* #param {Array} commands Array of commands
*/
const addToSet = (userkey, commands) => {
mySet.add(userkey);
if (typeof mySetMetadata[userkey] === 'undefined') {
mySetMetadata[userkey] = commands;
} else {
mySetMetadata[userKey] = [...mySetMetadata[userKey], ...commands]
}
}
// Populate with demo data
addToSet('user1', ['value#1', 'value#2', 'value#N']);
addToSet('user2', ['value#2', 'value#N']);
addToSet('user3', ['value#N']);
// Set up a timeout for a given user + key
setTimeout(() => {
removeFromSet('user1', 'value#2');
}, 5000);
Related
I have a function where I have to return for each "subcontractor" its response for each selection criteria.
Subcontractor object contains a selectionCriteria object. selectionCriteria object contains an array of data for each selectionCriteria a user has responded to.
Each array item is an object, that contains files, id, request (object that contains info about selection criteria user is responding to), response (contains value of the response).
Here is an example of how a subcontractor looks:
This is the function I come up with, but it's quite complex:
const { subcontractors } = useLoaderData<typeof loader>();
const { t } = useTranslation();
const submittedSubcontractors = subcontractors.filter(
(s) => s.status === 'submitted'
);
const subcontractorsResponsesToSelectionCriteria: Array<ISubcontractor> = [];
let providedAnswersResponded: boolean | null = null;
let providedAnswersFiles: Array<IFile> | [] = [];
let providedAnswersRequiresFiles: boolean | null = null;
submittedSubcontractors.forEach((u) => {
u.selectionCriteria.forEach((c) => {
if (c.request.id === criteriaId) {
if (c.response && 'answer' in c.response) {
if (typeof c.response.answer === 'boolean') {
providedAnswersResponded = c.response.answer;
} else {
providedAnswersResponded = null;
}
} else {
providedAnswersResponded = null;
}
providedAnswersFiles = c.files;
providedAnswersRequiresFiles = c.request.are_files_required;
subcontractorsResponsesToSelectionCriteria.push(u as ISubcontractor);
}
});
});
How could I simplify this code by using .reduce() method, or maybe even better ideas?
You should start working on reducing the level of nesting in your if/else like so:
function getProvidedAnswersResponded(response: any) {
if (response && ('answer' in response) && (typeof response.answer === 'boolean')) {
return response.answer;
}
return null;
}
submittedSubcontractors.forEach(u => {
u.selectionCriteria.forEach(c => {
if (c.request.id !== criteriaId) {
return;
}
providedAnswersResponded = getProvidedAnswersResponded(c.response);
providedAnswersFiles = c.files;
providedAnswersRequiresFiles = c.request.are_files_required;
subcontractorsResponsesToSelectionCriteria.push(u);
});
});
The strategy followed was basically to invert the special cases (such as c.requet.id === criteriaId) and exit the function immediately.
Also, extracting the "provided answer responded" function seems atomic enough to move it to a separate block, giving it more verbosity about what that specific code block is doing.
My code checks if a user is available. See snippet below:
const users = ['user1', 'user2', 'user3', 'user4']
const usersToAdd = 2
const getRandomWorker = (userArray) => {
return userArray[Math.floor(userArray.length * Math.random())]
}
const availableUsers = []
for (let i = 0; i < usersToAdd; i += i) {
let randomWorker = getRandomWorker(users)
let didAddWorker = false
while (!didAddWorker) {
if (checkIfUserAvailable(randomWorker)) {
availableUsers.push(randomWorker)
users = users.filter((user) => user !== randomWorker)
didAddWorker = true
} else if (!users.length) {
didAddWorker = true
} else {
users = users.filter((user) => user !== randomWorker)
}
}
}
My only problem is that it contains unsafe references to variables(s) because I get the following error:
Function declared in a loop contains unsafe references to variable(s) randomWorker.
I've searched around and fiddled with my code but I can't get rid of the error. I don't know where to look anymore.
As T.J Crowder suggested I had to make a function outside of the loop:
const filterOut = (array, target) => array.filter(element => element !== target);
That fixed it. A bit strange but I can continue know. Thanks!
i am planning to create an array of only 5 elements max in firestore like this
Array a = [1,2,3,4,5]
then add element 6 it will look like this
Array a = [2,3,4,5,6]
This cloud function (found here: https://github.com/firebase/functions-samples/blob/master/limit-children/functions/index.js) does what you want in Realtime Database:
'use strict';
const functions = require('firebase-functions');
// Max number of lines of the chat history.
const MAX_LOG_COUNT = 5;
// Removes siblings of the node that element that triggered the function if there are more than MAX_LOG_COUNT.
// In this example we'll keep the max number of chat message history to MAX_LOG_COUNT.
exports.truncate = functions.database.ref('/chat').onWrite((change) => {
const parentRef = change.after.ref;
const snapshot = change.after
if (snapshot.numChildren() >= MAX_LOG_COUNT) {
let childCount = 0;
const updates = {};
snapshot.forEach((child) => {
if (++childCount <= snapshot.numChildren() - MAX_LOG_COUNT) {
updates[child.key] = null;
}
});
// Update the parent. This effectively removes the extra children.
return parentRef.update(updates);
}
return null;
});
I believe you can adapt it for Firestore.
I am trying to create a serverless React app to make recommendations by processing some data from Spotify's API. I am using spotify web api js as a wrapper to make the API calls. My problem is that one of the results I get from my functions appears when I call console.log on it, but not when I pass it to another function. Here's the code for the submit handler on my page:
handleSubmit(e) {
e.preventDefault();
this.setState({recOutput: {}});
spotify.setAccessToken(this.props.vars.token);
spotify.searchArtists(this.state.artist)
.then(res => this.getRecs(res))
.then(output => this.processResults(output))
.then(processed => this.setState({resultReceived: true, recOutput: processed}))
.catch(err => this.handleError(err));
}
And here are all the functions it's calling:
/**
* Gets recommendations for a specific artist and outputs recOutput value in redux store
* #param {string} name The name of the artist
* #return Promise with output
* TODO: catch errors again lol
* /
**/
async getRecs(name) {
const MAX_SONGS = 50;
var output = {};
spotify.searchPlaylists(name, {limit: 1})
.then(searchTotal => {spotify.searchPlaylists(name, {limit: 50, offset: Math.floor(Math.random() * (searchTotal.playlists.total/50))}).then(
res => {
for (let i of res.playlists.items) {
spotify.getPlaylistTracks(i.id).then(
pt => {
let curSongs = 0;
if (pt == undefined) {
return;
}
for (let track of pt.items) {
if (curSongs > MAX_SONGS) break;
if (track.track != null
&& track.track.artists[0].name !== name
&& track.track.artists[0].name !== "") {
if (track.track.artists[0].name in output) {
output[track.track.artists[0].name]++;
} else {
output[track.track.artists[0].name] = 1;
}
}
curSongs++;
}
})
}
}
)
}).catch(err => this.handleError(err));
return output;
}
/**
* Processes results from our query to spotify, removing entries beyond a certain threshhold then sorting the object.
* #return Promise for updated results update
*/
async processResults(input) {
debugger;
let processed = {};
for (let key in input) {
console.log(key);
if (input[key]> 10) {
processed.key = input.key;
}
}
return processed;
}
My problem is that when I call .then(output => this.processResults(output)), the process method receives an empty output in the debugger, but when I call .then(output => console.log(output)), I see the expected output for the function.
Here is the context of my component:
I have following code which process a queue and I need to exist the function when there are no messages in the queue and there is no enough time to process more messages. My problem is, it doesn't jump out of the function upon failing the condition and I think it's due to that this a recursive function but I cannot figure it out.
/**
* Check if there is enough time to process more messages
*
* #param {} context
* #returns {boolean}
*/
async function enoughTimeToProcess(context) {
return context.getRemainingTimeInMillis() > 230000;
}
/**
* Consume the queue and increment usages
*
* #param context
*
* #returns {boolean}
*/
async function process(context) {
const messagesPerRequest = queueConst.messagesPerRequest;
const messagesToBeDeleted = [];
const queue = new queueClient();
const messages = await queue.getMessages(messagesPerRequest);
if (messages === undefined) {
if (await enoughTimeToProcess(context) === true) {
await process(context);
} else {
return false;
}
}
const responses = messages.map(async(messageItem) => {
const messageBody = JSON.parse(messageItem.Body);
const parsedMessage = JSON.parse(messageBody.Message);
const accountId = parsedMessage[0].context.accountId;
let code = parsedMessage[0].context.code;
// Our DB support only lowercase characters in the path
code = code.toLowerCase();
const service = parsedMessage[0].name;
const count = parsedMessage[0].increment;
const storageResponse = await incrementUsage(
{ storageClient: storage, code, accountId, service, count }
);
if (storageResponse) {
messagesToBeDeleted.push({
Id: messageItem.MessageId,
ReceiptHandle: messageItem.ReceiptHandle,
});
}
return 1;
});
const processedMessages = await Promise.all(responses);
const processedMessagesCount = processedMessages.length;
if (messagesToBeDeleted.length > 0) {
console.log(`${processedMessagesCount} messages processed.`);
await queue.deleteMessageBatch(messagesToBeDeleted);
}
if (await enoughTimeToProcess(context) === true) {
await process(context);
}
return true;
}
I think the problem can be when messages are undefined and there is still enough time, because the recursive function is going to be called infinite times, because it always accomplishes both conditions, and probably it exceeds the available resources.
Try to sleep some time before calling process function again, just to be sure it is the problem