Clear multiple lines from stdout - node.js

I am trying to write multiple lines to the console in Node.JS then clear all of the lines I wrote.
process.stdout.write(['a', 'b', 'c'].join('\n'))
setInterval(() => {
process.stdout.clearLine(0);
process.stdout.write(['d', 'e', 'f'].join('\n'));
}, 1000)
I've seen some solutions that clear the whole console, I do not want this. I just want to clear what I've written to the screen.

I don't know of there is better way to do this, but what I do is move the cursor up 1 line at the time and than clear that line.
const clearLines = (n) => {
for (let i = 0; i < n; i++) {
//first clear the current line, then clear the previous line
const y = i === 0 ? null : -1
process.stdout.moveCursor(0, y)
process.stdout.clearLine(1)
}
process.stdout.cursorTo(0)
}

Related

Merge json array object to itself

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);

Why would a function called from another not show in the profile output of a node app?

I have a NodeJS program. This is a trimmed down version of a much larger program with a lot of complexity that's irrelevant to this question removed. It goes through lists looking for matching objects:
/**
* Checks that the given attributes are defined in the given dictionaries
* and have the same value
*/
function areDefinedAndEqual(a, b, keys) {
return (
a &&
b &&
keys
.map(function (k) {
return a[k] && b[k] && a[k] === b[k]
})
.reduce(function (a, b) {
return a && b
}, true)
)
}
function calculateOrder() {
const matchingRules = [
{
desc: 'stuff, more stuff and different stuff',
find: (po, dp) => areDefinedAndEqual(po, dp, ['stuff', 'more_stuff', 'different_stuff'])
},
{
desc: 'stuff and different stuff',
find: (po, dp) => areDefinedAndEqual(po, dp, ['stuff', 'different_stuff'])
},
{
desc: 'just stuff',
find: (po, dp) => areDefinedAndEqual(po, dp, ['stuff'])
}
]
let listOfStuff = []
listOfStuff[999] = { stuff: 'Hello' }
listOfStuff[9999] = { stuff: 'World' }
listOfStuff[99999] = { stuff: 'Hello World' }
// Run through lots of objects running through different rules to
// find things that look similar to what we're searching for
for (let i = 0; i < 100000000; i++) {
for (let j = 0; j < matchingRules.length; j++) {
if (matchingRules[j].find({ stuff: 'Hello World' }, listOfStuff[i])) {
console.log(`Found match at position ${i} on ${matchingRules[j].desc}`)
}
}
}
}
calculateOrder()
Now all calculateOrder does is repeatedly call functions listed under matchingRules which in turn call areDefinedAndEqual which does some actual checking.
Now if I run this as follows:
richard#sophia:~/cc/sheetbuilder (main) $ node --prof fred.js
Found match at position 99999 on just stuff
richard#sophia:~/cc/sheetbuilder (main) $
I get just what I'd expect. So far so good.
I can then run the profile output through prof-process to get something more readable.
node --prof-process isolate-0x57087f0-56563-v8.log
However if I look at the output, I see this:
[JavaScript]:
ticks total nonlib name
4197 46.0% 89.0% LazyCompile: *calculateOrder /home/richard/cogcred/eng-data_pipeline_misc/sheetbuilder/fred.js:19:24
All the time is being spent in calculateOrder. I'd expect to see a large %age of the time spent in the various "find" functions and in areDefinedAndEqual but I don't. There's no mention of any of them at all. Why? Are they potentially being optimized out / inlined in some way? If so, how do I begin to debug that? Or is there some restrictions on certain functions not showing in the output? In which case, where are those retrictions defined? Any pointers would be much appreciated.
I'm running Node v16.5.0
Functions show up in the profile when tick samples have been collected for them. Since sample-based profiling is a statistical affair, it could happen that a very short-running function just wasn't sampled.
In the case at hand, inlining is the more likely answer. Running node with --trace-turbo-inlining spits out a bunch of information about inlining decisions.
If I run the example you posted, I see areDefinedEqual getting inlined into find, and accordingly find (and calculateOrder) are showing up high on the profile. Looking closely, in the particular run I profiled, areDefinedEqual was caught by a single profiler tick -- before it got inlined.

baconjs: throttle consecutive events with criteria

I'm coding a messaging app with Node.js and I need to detect when the same user sends N consecutive messages in a group (to avoid spammers). I'm using a bacon.js Bus where I push the incoming messages from all users.
A message looks like this:
{
"text": "My message",
"user": { "id": 1, name: "Pep" }
}
And this is my working code so far:
const Bacon = require('baconjs')
const bus = new Bacon.Bus();
const CONSECUTIVE_MESSAGES = 5;
bus.slidingWindow(CONSECUTIVE_MESSAGES)
.filter((messages) => {
return messages.length === MAX_CONSECUTIVE_MESSAGES &&
_.uniqBy(messages, 'user.id').length === 1;
})
.onValue((messages) => {
console.log(`User ${__.last(messages).user.id}`);
});
// ... on every message
bus.push(message);
It creates a sliding window, to keep only the number on consecutive messages I want to detect. On every event, it filters the array to let the data flow to the next step only if all the messages in the window belong to the same user. Last, in the onValue, it takes the last message to get the user id.
The code looks quite dirty/complex to me:
The filter doesn't look very natural with streams. Is there a better way to emit an event when N consecutive events match some criteria? .
Is there a better way to receive just a single event with the user (instead of an array of messages) in the onValue function.
It doesn't really throttle. If a user sends N messages in one year, he or she shouldn't be detected. The stream should forget old events somehow.
Any ideas to improve it? I'm open to migrating it to rxjs if that helps.
Maybe start with
latestMsgsP = bus.slidingWindow(CONSECUTIVE_MESSAGES)
.map(msgs => msgs.filter(msg => msgAge(msg) < AGE_LIMIT))
See if we should be blockking someone
let blockedUserIdP = latestMsgsP.map(getUserToBlock)
Where you can use something shamelessly imperative such as
function getUserToBlock(msgs) {
if (msgs.length < CONSECUTIVE_MESSAGES) return
let prevUserId;
for (var i = 0; i < msgs.length; i++) {
let userId = msgs[i].user.id
if (prevUserId && prevUserId != userId) return
prevUserId = userId
}
return prevUserId
}
Consider mapping the property you’re interested in as early as possible, then the rest of the stream can be simpler. Also, equality checks on every item in the sliding window won’t scale well as you increase the threshold. Consider using scan instead, so you simply keep a count which resets when the current and previous values don’t match.
bus
.map('.user.id')
.scan([0], ([n, a], b) => [a === b ? n + 1 : 1, b])
.filter(([n]) => n >= MAX_CONSECUTIVE_MESSAGES)
.onValue(([count, userId]) => void console.log(`User ${userId}`));

not equal to not working in postgresql query

if (req.body.positionDetails && req.body.positionDetails.length > 0) {
let total = req.body.positionDetails.length;
for (let i = 0; i < total; i++) {
db.query('SELECT * FROM position WHERE position <> $1',[req.body.positionDetails[i].position],function(err,p) {
console.log(p.rows)
});
}
}
It is selecting all the values from the database without checking the condition. How to solve this??
data is like
"positionDetails":[{"position":"manager"},{"position":"developer"}] and it is from postman.
Your prepared statement looks off to me. Try using ? as a placeholder for the position in your query.
db.query(
'SELECT * FROM position WHERE position <> ?', [req.body.positionDetails[i].position],
function(err, p) {
console.log(p.rows)
});
If this fixes the problem, then I suggest that you were comparing the position against the literal string $1, and every comparison failed resulting in every record appearing in the result set.

NodeJS for-loop unsuccessful at trimming urls that end in with numbers

I'm trying to take a group of Facebook Page urls and extract only the entity title of the page. Ie for 'https://www.facebook.com/BalanceSpaBoca' I'm looking only for 'BalanceSpaBoca.' This script works great for most of the sample data I'm using (the testFBurls array), printing only the trimmed string. For others, though, it prints both the trimmed string and the original string. It seems like all of the urls that get printed twice end with a string of numbers, but I'm not sure why that should make any difference in how the program runs.
var testFBurls = [
'http://www.facebook.com/pages/A-Yoga-Way/361702000576231',
'http://www.facebook.com/aztigurbansalon',
'https://www.facebook.com/pages/Azzurri-Salon-Spa/542579982495983',
'https://www.facebook.com/BalanceSpaBoca',
'https://www.facebook.com/BocaAmericanNailsandSpa',
'http://www.facebook.com/beachyogagirl',
'https://www.facebook.com/pages/Beauty-of-Wax/156355679240',
'http://www.facebook.com/beehivefitness.boca',
'https://www.facebook.com/pages/Believe-Day-Spa-Boutique/197615685896',
'https://www.facebook.com/photo.php?fbid=10151725966640897&set=a.10151725965355897.1073741828.197615685896&type=1&theater',
'http://facebook.com/pages/bigfoot-spa/1486364798260300',
'http://www.facebook.com/bloheartsyou',
'http://www.facebook.com/pages/The-Wellness-Center-Of-Boca-Raton/170371382995576',
'https://www.facebook.com/TherapyBodyBalanced',
'https://www.facebook.com/pages/BodyVital-Massage/177664492277158',
'https://www.facebook.com/bodyworkmall',
'https://www.facebook.com/pages/The-Bombay-Room-Yoga-Studio/148731658497764',
];
var possibleFBurlStarts = [
"https://www.facebook.com/",
"http://www.facebook.com/",
"https://www.facebook.com/pages/",
"http://www.facebook.com/pages/",
];
for (var count=0; count<testFBurls.length; count++){
var currentURL = testFBurls[count];
if (currentURL.indexOf(".com/photo") > -1) {
testFBurls.splice(i, 1);
i--;
}
for (var i=0; i < possibleFBurlStarts.length; i++){
var indexOfSubstring = currentURL.indexOf(possibleFBurlStarts[i]);
if (indexOfSubstring > -1) {
var res = currentURL.replace(possibleFBurlStarts[i], "");
}
}
if (count == testFBurls.length-1){
console.log(testFBurls);
}
}
Here's my console output
pages/A-Yoga-Way/361702000576231
A-Yoga-Way/361702000576231
aztigurbansalon
pages/Azzurri-Salon-Spa/542579982495983
Azzurri-Salon-Spa/542579982495983
BalanceSpaBoca
BocaAmericanNailsandSpa
beachyogagirl
pages/Beauty-of-Wax/156355679240
Beauty-of-Wax/156355679240
beehivefitness.boca
pages/Believe-Day-Spa-Boutique/197615685896
Believe-Day-Spa-Boutique/197615685896
bloheartsyou
pages/The-Wellness-Center-Of-Boca-Raton/170371382995576
The-Wellness-Center-Of-Boca-Raton/170371382995576
TherapyBodyBalanced
pages/BodyVital-Massage/177664492277158
BodyVital-Massage/177664492277158
bodyworkmall
pages/The-Bombay-Room-Yoga-Studio/148731658497764
The-Bombay-Room-Yoga-Studio/148731658497764
Notice that the first url is listed twice (first in its original form, and secondly in its truncated form), but then the second url (the third line in the output) is listed in truncated form alone. Any ideas what is causing this disparity? Only the truncated url should be printed.
You're modifying the array you're iterating through while you're iterating through it: testFBurls.splice(i, 1); which is typically a not-great thing to do. In any case, I think you should be able to accomplish your goal a lot easier with a simple regular expression:
for (var count=0; count<testFBurls.length; count++){
var matches = testFBurls[count].match(/^https?\:\/\/www\.facebook\.com\/(?:pages\/)?([^\/]+)/);
if (matches) {
console.log('found it:', matches[1]);
}
}

Resources