Replacing ObjectId with a string in JSON. Using RegEx

Problem: I have a data dump of a MongoDb query in a JSON file. I need to replace the ObjectID(“12345677abc”) with “12345677abc”.

Using Visual Studio Code’s find and replace

Find:

ObjectId\("([0-9a-fA-F]{24})"\)

Replace with: “$1”

Turns this

"_id" : ObjectId("5e3b1890e032d225a091d43f"),
"userId" : ObjectId("65ed1c2c-922c-4c82-b5bc-7324f69eea10"),

To this

"_id" : "5e3b1890e032d225a091d43f",
"userId" : "65ed1c2c-922c-4c82-b5bc-7324f69eea10",


Bonus:

ISODate\("([^"]+)"\)

Another cURL: This time validating TLS versions

I had to demonstrate that our hosting of a single page app did not accept TLS version 1.1,

This is the proof

curl -o /dev/null -s -w "%{http_code}\n" https://koala-moon.com --insecure --tls-max 1.1
Returns: 0000

curl -o /dev/null -s -w "%{http_code}\n" https://koala-moon.com --insecure --tls-max 1.2
Returns: 200

Easy eh?

JS Sorting with .localCompare

I’ve been using Javascript for 2 years now and can not remember ever having to sort collections. 95% of what I am doing is backend services work and I try to off load as much data manipulation to the databases, but this week I have had 7 instances of having to sort data.

This caught me out:

For a given collection:

const collection = [ {name: "Dave"}, {name: "Donna"}, {name: "dave"}, {name: "Derek"}, {name: "Dave"},];

Sorted with:

collection.sort(
  (a,b) => { 
    if (a.name < b.name) return -1; 
    if (a.name > b.name) return 1; 
    return 0;
  })

Returns this:

[ { name: 'Dave' },  { name: 'Dave' },  { name: 'Derek' },  { name: 'Donna' },  { name: 'dave' } ]

Which is not what I need.

.localCompare to the rescue

collection.sort(
  (a, b) => a.name.localeCompare(b.name)
)

Returns this:

[ { name: 'dave' },  { name: 'Dave' },  { name: 'Dave' },  { name: 'Derek' },  { name: 'Donna' } ] 

But there is more

.localCompare method has additional options. For the same collection above, this

collection.sort(
  (a, b) => a.name.localeCompare(b.name, 'en', { sensitivity: 'base' })
)

Returns this:

[ { name: 'Dave' },  { name: 'Dave' },  { name: 'dave' },  { name: 'Derek' },  { name: 'Donna' } ] 

Be aware that full implementation of .localCompare in Node.js is dependant on the version you are running.

Quick1: JS funky date requirement

The problem is:

Take a date object, set the time to 09:15 the following day. If that day is a Saturday, Sunday or Monday bump the date to the next Tuesday.

Solution:

const reminderTime = (date: Date): Date => {
  const response = new Date(date);
  
  const SUNDAY = 0;
  const MONDAY = 1;
  const TUESDAY = 2;
  const SATURDAY = 6;
  
  response.setDate(response.getDate() + 1);
  
  if ([SUNDAY, MONDAY, SATURDAY].some((x) => x === response.getDay())) {
    response.setDate(response.getDate() + ((TUESDAY + 7 - response.getDay()) % 7));
  }

  response.setHours(9);
  response.setMinutes(15);

  return response;
};

Is the date local or UTC? That depends on how the Date object passed into the method was created. In either case local or UTC is preserved.

Here are some proofs:

console.log(reminderTime(new Date(2020, 10, 2))); 
// Returns Tue Nov 03 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 10, 3)));
// Returns Wed Nov 04 2020 09:15:00 GMT+0000 (Greenwich Mean Time)

console.log(reminderTime(new Date(2020, 10, 4))); 
// Returns Thu Nov 05 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 10, 5)));
// Returns Fri Nov 06 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 10, 6)));
// Returns Tue Nov 10 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 10, 7)));
// Returns Tue Nov 10 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 10, 8)));
// Returns Tue Nov 10 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 10, 9)));
// Returns Tue Nov 10 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 11, 31)));
// Returns Fri Jan 01 2021 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 1, 29)));
// Returns Tue Mar 03 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

console.log(reminderTime(new Date(2020, 1, 30)));
// Returns Tue Mar 03 2020 09:15:00 GMT+0000 (Greenwich Mean Time) 

Quick1: JS Order array of Date objects

Solution: (Typescript)

(range as Date[]).sort((a, b) => a.valueOf() - b.valueOf());

My first thought was why not just:

(range as Date[]).sort()

But that does not work. Have a look at the MDN documents and you will see the comparison is done with character’s Unicode code.

Try this in your browsers console to see the solution working

const range = [
  new Date("2020-09-10"),
  new Date("2020-12-20"),
  new Date("2020-11-12"),
];

range.sort((a, b) => a.valueOf() - b.valueOf())

Quick1: JS array of dates

I always disliked dates in JS, but as time goes by confidence grows. It does not help that I avoid reaching for external packages unless it is really necessary.

Today I needed to generate arrays of numbers that represent days between two dates.

// Outcome needed. Inputs 2020-10-28 and 2020-11-06
const labels = [28,29,30,13,1,2,3,4,5,6];

// Solution
export const getDatesBetweenDates = (
  startDate: string,
  endDate: string
): number[] => {
  const dates: number[] = [];
  const start = new Date(startDate);
  const end = new Date(endDate);
  while (start <= end) {
    dates.push(start.getDate());
    start.setDate(start.getDate() + 1);
  }
  return dates;
};

I have no idea why I thought that would be hard

Quick1: JS, Remove duplicates from an array

There are many ways to do this by looping over the array, then using something like .some() or .findIndex().

How about this as an elegant and simple solution?

[...new Map(users.map((item) => [item.id, item])).values()]

The use case is a collection of aggregated data that could have multiple copies of a user. I needed to remove duplicates:

const users = [
  {id: "1234", name: "kirk"},
  {id: "6789", name: "spock"},
  {id: "1234", name: "kirk"},
  {id: "1234", name: "kirk"},
  {id: "rtyu", name: "bones"},
]

console.log([...new Map(users.map((item) => [item.id, item])).values()])

Copy and paste the code below into your browser console pane to see it work


const users = [
  {id: "1234", name: "kirk"},
  {id: "6789", name: "spock"},
  {id: "1234", name: "kirk"},
  {id: "1234", name: "kirk"},
  {id: "rtyu", name: "bones"},
]

[...new Map(users.map((item) => [item.id, item])).values()]

Quick1: JS + Vue.js pause before

Problem:

I had a large list that a user could reorder by dragging and dropping. All work beautifully.

Except persisting the changes to the database. I did not want the an API call for every drop action or a button that the user clicked that said, “Save list”.

Solution:

Its a Vue.js project and the drag and drop had two events called “start” and “end”. These would call the corresponding methods below.

“endDrag” starts a timer that will run the supplied method in 1.5 seconds after the dragging has stopped. If the user starts “dragging” again the timer is cancelled

methods: {
    endDrag(): void {
      this.timer = setTimeout(this.distpatchOrderedList, 1500);
      this.drag = false;
    },
    startDrag(): void {
      clearTimeout(this.timer);
      this.drag = true;
    },
   distpatchOrderedList(): void {
     // Do some magic
   }
}

Quick1: Typescript

I’ve been using Typescript for 12 months and every now and then I get blocked. I used to do a fair bit of ‘typescript ignore’ in my code just to keep things moving and depend on my tests to throw up mistakes.

This I think ha caught me out a few times in different circumstances.

interface Options {
  id: string;
  name: string;
}
const options: Options = {id: "qwerty", name: "andy pandy"}

Object(options).forEach(key => {
  localOptions[key] = options[key]
});

The above would not compile and give the following message (note if I set the line to be ignored the code still worked)

Element implicitly has an ‘any’ type because expression of type ‘string’ can’t be used to index type ‘xxxx’. No index signature with a parameter of type ‘string’ was found on type ‘xxxx’

So how to comply with Typescript?

I found two options. One went about extending the object constructor and adding overloads the second is type-casting. Extending the object constructor is probably more “correct” but type-casting worked and when you read the code it simpler to understand (IMHO)

interface Options {
  id: string;
  name: string;
}
const options: Options = {id: "qwerty", name: "andy pandy"}

Object(options).forEach(key => {
  localOptions[key as keyof Options] = options[key as keyof Options]
});

Does it work and does it address the issue? Yes it does.