Skip to main content
The @feathersjs/mongodb adapter provides native MongoDB integration for Feathers services, supporting all MongoDB features including aggregation pipelines, GridFS, and transactions.

Installation

1

Install dependencies

Install the MongoDB adapter and the MongoDB driver:
npm install @feathersjs/mongodb mongodb
2

Connect to MongoDB

Create a MongoDB connection:
import { MongoClient } from 'mongodb'

const client = new MongoClient('mongodb://localhost:27017/mydb')
await client.connect()

const db = client.db()
3

Create a service

Create a service using the MongoDB adapter:
import { MongoDBService } from '@feathersjs/mongodb'

class UserService extends MongoDBService {
  // Custom methods here
}

app.use('users', new UserService({
  Model: db.collection('users'),
  paginate: {
    default: 10,
    max: 50
  }
}))

Configuration

Service Options

The MongoDB adapter accepts these options:
interface MongoDBAdapterOptions {
  Model: Collection | Promise<Collection>  // MongoDB collection
  id?: string                              // Primary key field (default: '_id')
  disableObjectify?: boolean               // Don't convert IDs to ObjectId
  useEstimatedDocumentCount?: boolean      // Use estimated count for performance
  paginate?: PaginationOptions             // Pagination settings
  multi?: boolean | string[]               // Allow multi operations
  events?: string[]                        // Custom events
}

Example Configuration

import { MongoDBService } from '@feathersjs/mongodb'

app.use('messages', new MongoDBService({
  Model: db.collection('messages')
}))

Querying

Basic Queries

The MongoDB adapter supports all standard Feathers query operators:
// Find all users
const users = await app.service('users').find({
  query: {}
})

// Find with filters
const activeUsers = await app.service('users').find({
  query: {
    status: 'active',
    age: { $gte: 18 }
  }
})

MongoDB-Specific Options

Pass native MongoDB options through params.mongodb:
// Find with MongoDB options
const users = await app.service('users').find({
  query: { status: 'active' },
  mongodb: {
    hint: { status: 1 },
    maxTimeMS: 5000,
    readPreference: 'secondary'
  }
})

// Create with write concern
const user = await app.service('users').create(
  { name: 'John', email: 'john@example.com' },
  {
    mongodb: {
      writeConcern: { w: 'majority', wtimeout: 5000 }
    }
  }
)

Aggregation Pipelines

Use MongoDB’s powerful aggregation framework with the pipeline parameter:
// Use aggregation pipeline
const results = await app.service('orders').find({
  pipeline: [
    { $match: { status: 'completed' } },
    {
      $group: {
        _id: '$customerId',
        totalSpent: { $sum: '$amount' },
        orderCount: { $sum: 1 }
      }
    },
    { $sort: { totalSpent: -1 } },
    { $limit: 10 }
  ]
})

Data Manipulation

Create

const user = await app.service('users').create({
  name: 'Alice',
  email: 'alice@example.com',
  age: 25
})

Update

// Replace entire document (except _id)
const updated = await app.service('users').update(
  '507f1f77bcf86cd799439011',
  {
    name: 'Alice Updated',
    email: 'alice.new@example.com',
    age: 26
  }
)

Patch

// Partial update
const patched = await app.service('users').patch(
  '507f1f77bcf86cd799439011',
  { status: 'verified' }
)

Remove

const removed = await app.service('users').remove(
  '507f1f77bcf86cd799439011'
)

ObjectId Handling

The adapter automatically handles ObjectId conversion:
import { ObjectId } from 'mongodb'

// These all work the same
await app.service('users').get('507f1f77bcf86cd799439011')
await app.service('users').get(new ObjectId('507f1f77bcf86cd799439011'))

// Query by ObjectId
const users = await app.service('users').find({
  query: {
    _id: { $in: [
      '507f1f77bcf86cd799439011',
      '507f1f77bcf86cd799439012'
    ]}
  }
})

// Disable automatic ObjectId conversion
app.use('users', new MongoDBService({
  Model: db.collection('users'),
  disableObjectify: true  // Keep IDs as strings
}))

Performance Optimization

Estimated Document Count

For large collections, use estimated count for better performance:
app.use('logs', new MongoDBService({
  Model: db.collection('logs'),
  useEstimatedDocumentCount: true,
  paginate: { default: 50, max: 100 }
}))

// Pagination will use estimatedDocumentCount()
// instead of countDocuments() - much faster but approximate
const logs = await app.service('logs').find({
  query: { $limit: 50 }
})

Field Projection

// Only select needed fields
const users = await app.service('users').find({
  query: {
    $select: ['name', 'email']  // Exclude large fields
  }
})

Indexes

Create indexes on your collections:
// Create indexes for better query performance
await db.collection('users').createIndex({ email: 1 }, { unique: true })
await db.collection('users').createIndex({ status: 1, createdAt: -1 })
await db.collection('posts').createIndex({ userId: 1, publishedAt: -1 })

Type Safety

Full TypeScript support with generics:
import { ObjectId } from 'mongodb'
import { MongoDBService, MongoDBAdapterParams } from '@feathersjs/mongodb'
import type { Params } from '@feathersjs/feathers'

interface User {
  _id: ObjectId
  email: string
  name: string
  age: number
  roles: string[]
  createdAt: Date
}

interface UserData {
  email: string
  name: string
  age: number
  roles?: string[]
}

interface UserParams extends MongoDBAdapterParams {
  user?: User
}

class UserService extends MongoDBService<User, UserData, UserParams> {
  async find(params?: UserParams) {
    // Fully typed
    return super.find(params)
  }
}

app.use('users', new UserService({
  Model: db.collection<User>('users')
}))

// Type-safe usage
const users: User[] = await app.service('users').find()
const user: User = await app.service('users').get(userId)

Error Handling

The adapter provides specific error handling:
import { errorHandler } from '@feathersjs/mongodb'

try {
  await app.service('users').create({
    email: 'duplicate@example.com'
  })
} catch (error) {
  // MongoDB errors are converted to Feathers errors
  // Duplicate key -> Conflict (409)
  // Invalid operation -> BadRequest (400)
  // Not found -> NotFound (404)
}

Next Steps

Knex Adapter

Learn about the SQL adapter

Common Patterns

Explore adapter patterns

Hooks

Add hooks to your services

Validation

Validate your data with schemas