Menu
CoddyTech

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');                            // false

findOne answers the first matching document, or null when none matches.

challenge icon

Challenge

Easy

This 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.

  1. In server.js, add a GET /books/:id route.
  2. 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.
  3. 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" }.
  4. When no book has that _id, respond with status 404 and an error, for example { "error": "No such book" }. Try it: Send GET /books and copy Dune's _id: the 24 characters after "_id":. Each Run gives the books new ids, so copy it again after every Run. Send GET /books/ followed by the id you copied: you get 200 and Dune. Send GET /books/42: you get 400. Send GET /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');
});
quiz iconTest yourself

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