Finding by ObjectId
Part of the Databases with MongoDB section of Coddy's Node.js journey. Lesson 7 of 29.
To answer one book, the server looks it up by _id, but the id arrives in the URL as text.
An _id that MongoDB creates is an ObjectId: a 12-byte value written as 24 hex characters: the digits 0 to 9 and the letters a to f. JSON shows it as a string, but in the database it is not one, so a filter with the plain text matches nothing. Turn the text into an ObjectId first. ObjectId.isValid says whether a text can be one, because new ObjectId throws on anything else.
import { ObjectId } from 'mongodb';
const text = '66f1c2a9e4b0a1b2c3d4e5f6';
await orders.findOne({ _id: new ObjectId(text) }); // the order, or null
await orders.findOne({ _id: text }); // null: text is not an ObjectId
ObjectId.isValid('42'); // falsefindOne answers the first matching document, or null when none matches.
Challenge
EasyThis step opens the course’s prepared bookshelf API project, rather than your project files from Inserting Documents (including server.js). Your earlier work stays in its own lesson. Read the supplied files before editing server.js. This copy contains the bookshelf list and insertion routes.
A client wants one book, chosen by its _id.
- In
server.js, add aGET /books/:idroute. - The id in the URL is text. Some text can never be an ObjectId, which is 24 characters of digits and the letters a to f. For that text, respond with status 400 and an error, using
sendError, for example{ "error": "Not a valid id" }. Check this before you build an ObjectId, because building one from bad text throws an error. - Otherwise, look the book up by its
_id. When you find it, respond with status 200 and the book:{ "_id": "6720a1f4c2b9e81d3a5f0c11", "title": "Dune", "author": "Frank Herbert", "year": 1965, "isbn": "9780441013593", "genre": "scifi" }. - When no book has that
_id, respond with status 404 and an error, for example{ "error": "No such book" }. Try it: SendGET /booksand copy Dune's_id: the 24 characters after"_id":. Each Run gives the books new ids, so copy it again after every Run. SendGET /books/followed by the id you copied: you get 200 and Dune. SendGET /books/42: you get 400. SendGET /books/000000000000000000000000: it is a valid id that no book has, so you get 404.
Try it yourself
import express from 'express';
import { MongoClient } from 'mongodb';
const client = new MongoClient('mongodb://localhost:27017');
const db = client.db('shelf');
const books = db.collection('books');
await books.insertMany([
{ title: 'Dune', author: 'Frank Herbert', year: 1965, isbn: '9780441013593', genre: 'scifi' },
{ title: 'Kindred', author: 'Octavia E. Butler', year: 1979, isbn: '9780807083697', genre: 'scifi' },
{ title: 'Emma', author: 'Jane Austen', year: 1815, isbn: '9780141439587', genre: 'classic' },
]);
const app = express();
app.use(express.json());
// Every error answers { error: message }.
function sendError(res, status, message) {
res.status(status).json({ error: message });
}
app.get('/', (req, res) => {
res.send('Bookshelf API');
});
app.get('/books', async (req, res) => {
const list = await books.find().toArray();
res.json(list);
});
app.post('/books', async (req, res) => {
const book = req.body;
await books.insertOne(book);
res.status(201).json(book);
});
app.listen(3000, () => {
console.log('Bookshelf is running on port 3000');
});
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Databases with MongoDB
Practice on your own: Express playground