0Pricing
MongoDB Academy · Leçon

Lire des documents avec le pilote Node.js

Vous connecterez un script Node.js à MongoDB et effectuerez des opérations d’insertion et de recherche à l’aide du pilote officiel.

Lire des documents avec le pilote Node.js est une leçon MongoDB Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage MongoDB Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours MongoDB Academy comprend 4 leçons au total.

Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.

The Official Node.js Driver

The MongoDB Node.js driver (mongodb npm package) is the official, low-level client for connecting to MongoDB from Node.js. It is maintained by MongoDB Inc., supports the full MongoDB API, and ships with TypeScript type definitions.

The driver exposes a MongoClient class that manages a connection pool—a set of pre-established TCP connections reused across requests. This eliminates the overhead of creating a new connection for every operation. Most production Node.js apps share a single MongoClient instance for the lifetime of the process.

# Install the MongoDB Node.js driver
npm install mongodb

# TypeScript types are included - no @types/mongodb needed

Creating a MongoClient and Connecting

Create a MongoClient with your connection string URI and call connect(). The connection is not established until connect() (or the first operation). Once connected, retrieve a database reference with client.db('dbName') and a collection reference with db.collection('collName').

Best practice: create the MongoClient once at application startup and export/inject it. Do NOT create a new client per request—this exhausts file descriptors and defeats the connection pool.

const { MongoClient } = require('mongodb');

const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017';
const client = new MongoClient(uri);

async function main() {
  await client.connect();
  console.log('Connected to MongoDB');

  const db = client.db('myapp');
  const users = db.collection('users');

  // ... perform operations ...

  await client.close();
}

main().catch(console.error);

Connection Pool and Options

The MongoClient maintains a connection pool of open TCP connections. When an operation needs to run, it borrows a connection from the pool, executes the operation, and returns the connection. Key pool options:

  • maxPoolSize (default 100): maximum simultaneous connections
  • minPoolSize (default 0): keep-alive connections when idle
  • connectTimeoutMS: how long to wait for initial connection
  • serverSelectionTimeoutMS: how long to wait if no server is reachable

For most Node.js web servers, the default pool size of 100 is appropriate. Serverless functions (AWS Lambda) should use smaller pools.

const client = new MongoClient(uri, {
  maxPoolSize: 20,           // Max 20 simultaneous connections
  minPoolSize: 5,            // Keep 5 alive when idle
  connectTimeoutMS: 5000,    // 5s to establish initial connection
  serverSelectionTimeoutMS: 5000  // 5s to select a server
});

// The client pool is shared across all operations
// Never create per-request clients!

insertOne and insertMany in Node.js

All driver operations return Promises. Use async/await for clean, readable code. The insert methods accept documents as plain JavaScript objects—the driver automatically serializes them to BSON.

The result objects include acknowledged (boolean) and insertedId/insertedIds. TypeScript users can pass a generic type parameter to get typed documents: db.collection<User>('users').

const db = client.db('shop');
const products = db.collection('products');

// insertOne
const { insertedId } = await products.insertOne({
  name: 'Wireless Mouse',
  price: 29.99,
  stock: 150,
  createdAt: new Date()
});
console.log('Inserted product:', insertedId);

// insertMany
const { insertedCount } = await products.insertMany([
  { name: 'Keyboard', price: 49.99, stock: 80 },
  { name: 'Monitor',  price: 299.99, stock: 25 }
]);
console.log('Inserted:', insertedCount);

findOne in Node.js

collection.findOne(filter, options) returns a Promise that resolves to the matching document or null. The optional options object accepts projection, sort, and maxTimeMS.

A common pattern in web APIs: look up a resource by its URL parameter (the id string), convert it to an ObjectId for the query, and return 404 if null is returned. Always validate that the id string is a valid ObjectId format before constructing one—invalid strings throw synchronously.

const { ObjectId } = require('mongodb');

// Express route handler example
app.get('/products/:id', async (req, res) => {
  let objId;
  try {
    objId = new ObjectId(req.params.id);
  } catch {
    return res.status(400).json({ error: 'Invalid product id' });
  }

  const product = await db.collection('products').findOne(
    { _id: objId },
    { projection: { name: 1, price: 1, stock: 1, _id: 0 } }
  );

  if (!product) return res.status(404).json({ error: 'Not found' });
  res.json(product);
});

find() and Cursor in Node.js

In Node.js, collection.find(filter, options) returns a FindCursor. You iterate it with for await...of, call .toArray() to load all results, or use .forEach(callback). All options (sort, limit, skip, projection) can be passed in the options object or chained as methods.

For API list endpoints, .toArray() is convenient—just ensure you always apply .limit(n) to prevent loading unbounded result sets. For data processing jobs (exports, migrations), stream with for await...of.

// List endpoint with pagination
app.get('/products', async (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = 20;
  const skip = (page - 1) * limit;

  const products = await db.collection('products')
    .find({ stock: { $gt: 0 } })
    .sort({ price: 1 })
    .skip(skip)
    .limit(limit)
    .project({ name: 1, price: 1, _id: 1 })
    .toArray();

  res.json({ page, products });
});

Error Handling Patterns

All driver operations can throw errors: network issues, authentication failures, write conflicts, validation errors. Use try/catch around all database calls in production code. Key error types:

  • MongoNetworkError: connectivity problem—retry logic may help
  • MongoServerError code 11000: duplicate key violation
  • MongoServerError code 121: document failed schema validation

Build a withRetry wrapper for transient network errors. Do not retry validation or duplicate key errors—they indicate a logic bug, not a transient failure.

async function createUser(data) {
  try {
    const result = await db.collection('users').insertOne(data);
    return { id: result.insertedId };
  } catch (err) {
    if (err.code === 11000) {
      // Duplicate email
      throw new Error('EMAIL_IN_USE');
    }
    if (err.code === 121) {
      // Schema validation failed
      throw new Error('INVALID_DATA');
    }
    // Network or other error - let it propagate
    throw err;
  }
}

Handling ObjectId in API Responses

When returning MongoDB documents in a REST API response, ObjectId objects are serialized to a string representation by JSON.stringify, appearing as '64a2f3b1c9e7e12345678901'. Clients then send this string back as the ID in subsequent requests.

A common pattern is to transform documents in a mapping function: convert _id to id as a string, removing the MongoDB-specific underscore prefix that clients may find confusing. This also avoids leaking internal MongoDB implementation details to API consumers.

// Transform MongoDB document for API response
function toPublicUser(doc) {
  const { _id, passwordHash, ...rest } = doc;
  return {
    id: _id.toString(),  // ObjectId -> string
    ...rest              // All other fields, minus passwordHash
  };
}

const user = await db.collection('users').findOne({ email });
if (user) res.json(toPublicUser(user));

// Client sends 'id' string back:
// GET /users/64a2f3b1c9e7e12345678901
// Server converts: new ObjectId(req.params.id)

Sharing the Client Across Modules

The recommended Node.js pattern is to initialize MongoClient once and share it across modules using a singleton pattern or dependency injection. A common approach is a db.js module that exports a connectDB() function and a getDB() accessor.

Call connectDB() once at application startup (in server.js or app.js). All route handlers and service modules call getDB() to get the database reference without creating new connections.

// db.js - singleton pattern
const { MongoClient } = require('mongodb');
let db;

async function connectDB() {
  const client = new MongoClient(process.env.MONGODB_URI);
  await client.connect();
  db = client.db('myapp');
  console.log('MongoDB connected');
}

function getDB() {
  if (!db) throw new Error('DB not initialized - call connectDB() first');
  return db;
}

module.exports = { connectDB, getDB };

// Usage in a route:
// const { getDB } = require('./db');
// const db = getDB();
// await db.collection('users').find({}).toArray();

Graceful Shutdown

When your Node.js process receives a shutdown signal (SIGTERM, SIGINT), close the MongoClient gracefully with client.close(). This flushes pending write buffers, closes open cursors, and releases TCP connections cleanly.

Without graceful shutdown, MongoDB may see an abrupt disconnection, trigger error handling on in-flight operations, and the connection pool on the server side remains open until the idle timeout fires. In high-traffic systems, many abrupt shutdowns can exhaust MongoDB's connection limit.

// Graceful shutdown handlers
const client = new MongoClient(uri);
await client.connect();

process.on('SIGINT', async () => {
  console.log('Shutting down...');
  await client.close();
  process.exit(0);
});

process.on('SIGTERM', async () => {
  console.log('Received SIGTERM');
  await client.close();
  process.exit(0);
});

// Express:
const server = app.listen(3000);
process.on('SIGTERM', () => server.close(async () => {
  await client.close();
}));

TypeScript Integration

The MongoDB Node.js driver includes first-class TypeScript support. You can define an interface for your document shape and pass it as a generic to db.collection<MyType>(). The driver then provides type-safe results for findOne, find().toArray(), and more.

One subtlety: the TypeScript type must include _id?: ObjectId to match what MongoDB returns. When projecting out _id, TypeScript still includes it in the type—you may want to use WithId<T> or define separate input and output types for a fully type-safe implementation.

import { MongoClient, ObjectId } from 'mongodb';

// Define your document interface
interface User {
  _id?: ObjectId;
  name: string;
  email: string;
  age: number;
  createdAt: Date;
}

const users = db.collection<User>('users');

// Fully typed result
const user = await users.findOne({ email: 'alice@test.com' });
// user is User | null
if (user) console.log(user.name.toUpperCase()); // TypeScript knows name is string

Quick Check

Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.

Lesson Recap

In this lesson you learned: MongoClient manages a connection pool—create one instance at startup and share it across all modules to avoid connection overhead, all operations return Promises and should be awaited with try/catch for proper error handling, with error code 11000 indicating duplicate key violations, and TypeScript generics on collection<T>() provide type-safe document access with full IDE support. Next up we explore MongoDB's full suite of comparison and logical query operators to write precise, complex filters.

Questions Fréquemment Posées

La leçon « Lire des documents avec le pilote Node.js » est-elle gratuite ?

Oui — le texte complet de « Lire des documents avec le pilote Node.js » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours MongoDB Academy, passe à CoddyKit PRO. Le cours MongoDB Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Lire des documents avec le pilote Node.js » ?

Vous connecterez un script Node.js à MongoDB et effectuerez des opérations d’insertion et de recherche à l’aide du pilote officiel. Tu pratiques MongoDB Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer MongoDB Academy ?

Aucune expérience préalable n'est requise. MongoDB Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Lire des documents avec le pilote Node.js » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon MongoDB Academy ?

Oui. Chaque leçon MongoDB Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. insertOne et insertMany
  2. findOne et find : comprendre les curseurs
  3. Interroger des champs imbriqués et des tableaux
  4. Lire des documents avec le pilote Node.js
← Retour à MongoDB Academy