node.js: How to make a variable out of a text input? - node.js

I want a user to put in a name of a file, then copy the content into an array and save this array with the name of the input filename. Here is the code I am talking about:
The array "items" represents the user input. Right now those items are fed into my function "einlesen" which returns the array with the data. This data is now written into the same array results but I want it to be written into the arrays "GVZ", "TAL", and "XPG". Can someone help me out?
Grateful for every idea :)
Nils
var items = [['GZV', ';', 1, 2], ['TAL', '<|>', 1, 'n'], ['XPG', '<|>', 0, 2]];
var results = [];
items.forEach(function(item) {
einlesen.einlesen(item[0], item[1], item[2], item[3], function(err, result){
results.push(result[1][0]);
console.log(item[0]);
if(results.length == items.length) {
final();
}
})
});

You would be better off using an object instead of an array of arrays:
var items = {
GZV: [...],
TAL: [...],
XPG: [...]
}
for(item in items) {
einlesen.einlesen(...)
}
This way, you can create object properties based on user input. It is not possible to create a variable (presuming you mean variable name?) out of user input.
var newProp = "resultOfInput";
items[newProp] = [...];
console.log(items.resultOfInput) // [...]
If you're doing this, you need to ensure that there's strong validation on the input. For example; if the input contains any spaces this will prevent the property being accessed via dot notation. Worse still, duplicate user input could easily over-ride any existing properties in the array.

Related

mongodb pull is not removing all items

I'm working on a project in nodejs using mongodb as my database. I'm trying to get rid of elements within my array that have dates before today. The problem that I'm having is that at most 5 elements are being deleted. I want all elements that meet this criteria to be deleted. Also, when I don't have user.possible.pull(items._id) const result = await user.save() all elements that meet this criteria are shown in my deletePossible array. However, when I do have user.possible.pull(items._id) const result = await user.save() at most 5 are being shown as well.
In my database, my User document looks like:
_id: '',
name: '',
possible: Array
0 Object
date: "Tues Jan 10 2023",
_id: "63c0b169b6fa12ac49874a13"
1 Object
date: "Wed Jan 11 2023",
_id: "63c0b172b6fa12ac49874a32"
...
My code:
const user = await User.findById(args.userId)
const deletePossible = [];
for (var items of user.possible) {
if (+new Date(items.date) < +new Date().setHours) {
deletePossible.push(items._id)
user.possible.pull(items._id)
const result = await user.save()
}
}
`
console.log(deletePossible)
I've tried a number of things such as:
for (var item of deletePossible) {
user.possible.pull(item)
const result = await user.save()
}
following deletePossible.push(items._id), and
const userInfo = await User.updateOne( { _id: args.userId}, {possible:{$pull:[...deletePossible] }} )
which removes all of the arrays from possible regardless of if it's contained within deletePossible and then adds a random _id. Nothing I have tried seems to work. Does anyone have any idea why this is happening and how to get this to work properly? I would really appreciate any help or advice. Thank you!
You can simply filter user.possible and save the updated User:
const user = await User.findById(args.userId);
if (!user) return;
// Change the condition based on your needs
user.possible = user.possible.filter(p => new Date(p.date) >= new Date());
await user.save();
The core of the issue appears to not be related to Mongo or Mongoose really, but is rather just a standard algorithmic logic problem.
Consider the following code, which iterates over an array, logs each element, and removes the third element when it arrives at it:
const array = [0, 1, 2, 3, 4];
for (const element of array) {
console.log(element);
if (element === 2) {
array.splice(2, 1); // remove the element at index 2 from the array
}
}
This code outputs:
0
1
2
4
Notice anything interesting? 3 has been skipped.
This happens because deleting an element from an array causes everything in front of it to move up a position. So if you're looking at 2 and you delete it, then 3 moves into 2's place, and 4 moves into 3's place. So then if you look at the next position, you're now looking at 4, not 3. The code never sees the 3.
This is why you should never change an array while iterating over it. A lot of languages won't even allow you to (if you're using iterators), they'll throw some sort of "underlying collection was modified during iteration" error. You can make it work if you know what you're doing (often just by iterating over the array backwards), but there are usually better solutions anyway, like using Array.prototype.filter().
One easy solution is to iterate over a copy of the array, so that when you do the delete, the array you're iterating over (the copy) isn't changed. That would look like this:
for (const item of [...user.possible]) {
if (/* some condition */) {
user.possible.pull(item._id);
}
}
Another problem with your code: +new Date().setHours will always evaluate to NaN since setHours is a function and converting a function to a number always results in NaN. I suspect this is just a typo you introduced while struggling with the original issue.
The suggestion to use filter() is even better.

Create array and randomize node.js array

I'm trying to write a cisco webex bot which get all people in the space(room) and randomly write only one name.
I have this code
framework.hears("daily host", function (bot) {
console.log("Choosing a daily host");
responded = true;
// Use the webex SDK to get the list of users in this space
bot.webex.memberships.list({roomId: bot.room.id})
.then((memberships) => {
for (const member of memberships.items) {
if (member.personId === bot.person.id) {
// Skip myself!
continue;
}
let names = (member.personDisplayName) ? member.personDisplayName : member.personEmail;
let arrays = names.split('\n');
var array = arrays[Math.floor(Math.random()*items.length)];
console.log(array)
bot.say(`Hello ${array}`);
}
})
.catch((e) => {
console.error(`Call to sdk.memberships.get() failed: ${e.messages}`);
bot.say('Hello everybody!');
});
});
But this doesn't work.
Also name after i use let arrays = names.split('\n'); separated by space and don't have comma.
I think because of what code doesn't work
Output of console log:
[ 'George Washington' ]
[ 'John' ]
[ 'William Howard Taft' ]
Main question now how to turn output to array?
That's because arrays[Math.floor(Math.random()*items.length)] only assigns an array with length 3. You need to randomise the index and push to array or use a sort function on the original array
var array = arrays.sort((a,b)=>{
return Math.floor(Math.random()*arrays.length);
});
if you are looking to get the output as per you question you can use reduce instead of sort.
var arrays = [ 'George Washington', 'John', 'William Howard Taft'];
var array = arrays.reduce((a,i)=>{
if(!a) a = [];
a.splice(Math.floor(Math.random()*arrays.length), 0, [i]);
return a;
},[]);
Here is how to get a single name from your data, and ensuring it is a string. There are only four names in the array, so run the snippet several times if you keep getting the same name.
// A list of names. Notice that Arraymond is an array; the other names are strings.
const names = [ 'George Washington', 'John', 'William Howard Taft', ['Arraymond'] ];
// Randomize the names
const randomNames = names.sort(() => Math.random() - 0.5);
// Get the first name. Make sure the name is a string (not an array)
const name = randomNames[0].toString();
console.log(name)
A tip: don't name your array "array" or "arrays" - it is not meaningful. Use good naming conventions and meaningful variable names that help others understand what the code is doing.

Extract a substring in a NetSuite saved search

I have the following: Auto Parts : Manufacturers : Mercedes Benz
I need to extract the brand Mercedes Benz from this in a saved search inside NetSuite.
formulatext: TRIM(REGEXP_SUBSTR({yourfieldid}, '[^:]+$'))
First, we need to make the save search(according to the requirement).
var SaveSearch = nlapiSearchRecord("customer", null,
[
["email", "is", 'xyz#email.com']
],
[
new nlobjSearchColumn("firstname"),
new nlobjSearchColumn("lastname"),
new nlobjSearchColumn("email")
]);
if (SaveSearch) {
var data = getAllResults(SaveSearch, SaveSearch[0].getAllColumns());
}
In the above snippet, we make the save search and then check that if there something in the save search then it goes into the loop and calls the function that is getAllResults.
// calling the function
function getAllResults(SaveSearch, col) {
var array = [];
for (var i = 0; i < leadSearch.length; i++) {
array.push({
'firstname': leadSearch[i].getValue(col[0]),
'lastname': leadSearch[i].getValue(col[1]),
'email': leadSearch[i].getValue(col[2])
})
}
return array;
}
In this, we push the save search field into the array and make sure that is according to the column that we created while making save search otherwise value may be assigned to some other key.
Hope this helps.

$.unique(array) is not working for array elements having multiple words

var availableNames=['Hello India', 'Hello India', 'Test', 'Test']
$.unique(availableNames);
$("#corpName").autocomplete({
source : availableNames,
minLength : 4
});
availableNames is my array source for auto-complete. I want to show unique values in the list so called jquery unique function.
The unique function is working fine for single words like 'Hello' but not for two word strings like 'Hello India'. Its showing two 'Hello India' in dropdown and one 'Hello'.
Please Suggest me how to display only unique values in the drop-down list.
Thank You.
you have to write your own function. There are two ways to do that:
use filter:
// returns a new array with unique entries
Array.prototype.unique = function() {
return this.filter(function(el, index, oThis) {
return index === oThis.indexOf(el);
});
}
EDIT here is a real prototype version, that changes the original array
Array.prototype.unique2 = function() {
var c=this.length;
while(c--)
c===this.indexOf(this[c])||this.splice(c,1);
};
you can test both versions in this fiddle: http://jsfiddle.net/6mpqaxhk/

Node Redis: How to filter a sorted set of keys and retrieve each keys hashed values in one call

I am working with a redis database in node.js using node_redis. Here is a quick example of a structure similar to what I am using.
hmset('user:1234',
'user_id', 1234,
'user_name', billy,
'user_age', 16);
//add user to group 1 store their id with their age as their score
zadd(['group:1:users_by_age', 16, user:1234]);
hmset('user:1235',
'user_id', 1235,
'user_name', jake,
'user_age', 21);
//add user to group 1 store their id with their age as their score
zadd(['group:1:users_by_age', 21, user:1235]);
Now lets say I wanted to get all user data for users over the age of 18 in group:1
I know I can get the user keys by calling
postClient.zrangebyscore(
[ 'group:1:users_by_age', '18', '+inf'],
function( err, results ){
console.log(results);
}
);
Where I get lost is how do I fetch all the user objects at once?
To take it one step further, is it possible to both zrangebyscore and get all the userobjects in one call?
To take it one step further, is it possible to both zrangebyscore and get all the userobjects in one call?
I don't believe you can. The SORT command has GET functionality built in which allows you to do such a thing in one call, but there's no way to pipe the results of a ZRANGEBYSCORE into SORT (barring storing it in a temporary key and then using SORT on that key).
There's also no natural way to retrieve multiple hashes in one call.
With your current implementation, considering these limitations, you might get all the users with a multi, like:
postClient.zrangebyscore([...], function (err, results) {
var multi = postClient.multi();
for (var i=0; i<results.length; i++){
multi.hgetall(results[i]);
}
multi.exec(function(err, users){
console.log(users);
});
});
You could do this with a luascript though, retrieving the list of keys and iterating over it, calling hmget or hgetall on each key.
I do something like this in the following example, using hmget and specific keys.
Obvious disclaimer: I am not a lua programmer. Brief explanation: the script takes a start and end range for user age, then any number of hash keys which it uses for hmget on each user key, and appending it all to an array which will be wrapped up as user objects back in the javascript.
var script = '\
local keys = redis.call("ZRANGEBYSCORE", KEYS[1], ARGV[1], ARGV[2]); \
if not keys then return {} end; \
local users, attrs = {}, {} \
for i=3,#ARGV do \
table.insert(attrs, ARGV[i]) \
end \
for i,key in pairs(keys) do \
local vals = redis.call("HMGET", key, unpack(attrs)); \
if vals then \
for j,val in pairs(vals) do \
table.insert(users, val) \
end \
end \
end \
return users \
';
// The rest of this you'd probably want to wrap up in an async function,
// e.g `getUsersByRange`
// specify the user attributes you want
var attrs = ["id", "name", "age"];
// specify the range
var range = [18, "+INF"];
// get the attributes length, used to build the user objects
var attrlen = attrs.length;
// wrap up the params
var params = [script, 1, "users_by_age"].concat(range).concat(attrs);
// retrieve the user attributes in the form of [a1, a2, a3, a1, a2, a3, ... ],
// then collate them into an array of user objects like hgetall would return.
postClient.eval(params, function (err, res) {
var users = [], i, j, k;
for (i=0, j=0; i<res.length; i+=attrlen, j++) {
users[j] = {};
for (k=0; k<attrlen; k++) {
users[j][attrs[k]] = res[i+k];
}
// this should be a list of users
console.log(users);
}
});
Note that it would be trivial to process the users back into objects inside the lua script, but when being converted back to redis data structures, lua tables become redis multi bulk replies (arrays), and the structure would be lost. Because of that it's necessary to convert the multi bulk reply into user objects back in javascript.

Resources