Search
Part of the Node.js Basics section of Coddy's Node.js journey. Lesson 32 of 33.
With a few dozen notes, scrolling through list stops working: you need to search.
Lower both sides before comparing, so Milk, milk and MILK all match, then test with includes. Loop over the full list and keep each index, so a match shows the same number as in list, the one done and remind expect.
const songs = ['Blue Moon', 'Moonlight', 'Sunny'];
const query = 'MOON'.toLowerCase();
songs.forEach((title, i) => {
if (title.toLowerCase().includes(query)) {
console.log(`${i + 1}. ${title}`);
}
});Challenge
EasyWith many notes, scrolling through list stops working. Add a search command that finds notes by a word.
- In
notes.js, add asearchcommand. The words aftersearchare what to look for. - Find every note containing the search text, whatever the capitals:
milk,MilkandMILKall findBuy milk. - Print each match with
formatNote, using the number the note has inlist, so you can use that number withdoneandremind. Print the matches oldest first, in the order they are stored, even whensettings.jsonsortslistnewest first. Print no heading.
With the notes Buy milk, Call Ada and buy bread, node notes.js search buy prints:
1. Buy milk
3. buy breadnode notes.js search ADA prints 2. Call Ada.
- When no note matches, print
No notes matchfollowed by the search text.node notes.js search teaprints:No notes match tea
Try it: type search milk in the box after $ node notes.js and press Enter, then search MILK: both find the same notes. Then search for a word that is in none of your notes: you see No notes match and that word.
Try it yourself
// Your notes tool starts here.
import { rmSync } from 'node:fs';
import path from 'node:path';
import { formatNote } from './format.js';
import stats from './legacy/stats.cjs';
import pkg from './package.json' with { type: 'json' };
import store from './store.js';
const [command, ...words] = process.argv.slice(2);
const text = words.join(' ');
store.on('added', (note, n) => {
console.log(`Saved note ${n}.`);
});
const noteNumber = (word) => {
const n = Number(word);
if (!Number.isInteger(n) || n < 1 || n > store.notes.length) {
console.error(`No note ${word}`);
process.exit(1);
}
return n;
};
if (command === 'add') {
await store.add(text);
} else if (command === 'list') {
const owner = process.env.NOTES_OWNER ?? 'you';
console.log(`Notes for ${owner}`);
if (store.notes.length === 0) {
console.log('No notes yet');
}
const lines = store.notes.map((note, i) => formatNote(i + 1, note));
if (store.settings.sort === 'newest') {
lines.reverse();
}
lines.forEach((line) => console.log(line));
} else if (command === 'where') {
const file = path.join(process.cwd(), 'notes.json');
console.log(file);
console.log(path.basename(file));
} else if (command === 'stats') {
console.log(`${store.notes.length} notes, ${stats.countWords(store.notes)} words`);
} else if (command === 'done') {
const removed = await store.remove(noteNumber(words[0]));
console.log(`Done: ${removed}`);
} else if (command === 'remind') {
const note = store.notes[noteNumber(words[0]) - 1];
let count = 3;
const timer = setInterval(() => {
if (count > 0) {
console.log(count);
count -= 1;
} else {
console.log(note);
clearInterval(timer);
}
}, 200);
} else if (command === 'import') {
let input = '';
for await (const chunk of process.stdin) {
input += chunk;
}
const lines = input
.split('\n')
.map((line) => line.trim())
.filter((line) => line !== '');
for (const line of lines) {
await store.add(line);
}
console.log(`Imported ${lines.length} notes.`);
} else if (command === 'version') {
console.log(`${pkg.name} ${pkg.version}`);
} else if (command === 'clear') {
rmSync('notes.json', { force: true });
console.log('Deleted notes.json');
} else {
if (command) {
console.error(`Unknown command: ${command}`);
}
console.error('Usage: node notes.js <command> [words]');
process.exit(1);
}
All lessons in Node.js Basics
Practice on your own: Express playground