npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@omodaka/pinatinodb-adapter-mongoose

v0.1.0

Published

Mongoose adapter for PinatinoDB - automatically sync MongoDB data to IPFS

Downloads

18

Readme

@pinatinodb/mongoose-adapter

Automatically sync your Mongoose/MongoDB data to IPFS with zero code changes to your existing application.

🚀 Why This Adapter?

  • Zero Code Changes - Wrap your existing Mongoose models, that's it
  • Automatic Sync - All saves, updates, and deletes sync to IPFS
  • Perfect Fit - MongoDB's document model maps 1:1 to IPFS JSON
  • Selective Sync - Choose which models to sync
  • Type-Safe - Full TypeScript support
  • Production Ready - Error handling, logging, configurable strategies

📦 Installation

pnpm add @pinatinodb/mongoose-adapter @pinatinodb/core mongoose

🎯 Quick Start

import mongoose from 'mongoose';
import { withPinatino } from '@pinatinodb/mongoose-adapter';
import { PinatinoDB } from '@pinatinodb/core';

// 1. Create your Mongoose schema as usual
const UserSchema = new mongoose.Schema({
  name: String,
  email: String,
  age: Number
});

// 2. Initialize PinatinoDB
const pinatino = new PinatinoDB({
  pinata: { apiKey: process.env.PINATA_JWT! }
});
await pinatino.initialize();

// 3. Wrap your model with PinatinoDB
const User = withPinatino(mongoose.model('User', UserSchema), {
  pinatino,
  strategy: 'write-through',
  logging: true
});

// 4. Use Mongoose normally - data automatically syncs to IPFS!
const user = await User.create({
  name: 'Alice',
  email: '[email protected]',
  age: 28
});
// ✅ Now in both MongoDB AND IPFS!

🔧 Configuration

Basic Configuration

const User = withPinatino(mongoose.model('User', UserSchema), {
  pinatino, // PinatinoDB instance (required)
  strategy: 'write-through', // Sync strategy (optional)
  logging: true, // Enable logging (optional)
  onError: (error, operation, model) => {
    // Custom error handler (optional)
    console.error(`Error in ${model}.${operation}:`, error);
  }
});

Selective Model Sync

Only sync specific models:

// Wrap only the models you want to sync
const User = withPinatino(mongoose.model('User', UserSchema), {
  pinatino,
  models: ['User', 'Post'] // Only sync these
});

const Session = mongoose.model('Session', SessionSchema); // Not wrapped = not synced

Exclude Models

Sync all except specific models:

const User = withPinatino(mongoose.model('User', UserSchema), {
  pinatino,
  excludeModels: ['Log', 'Session', 'Cache'] // Skip these
});

🔄 Sync Strategies

Write-Through (Default)

Writes to both MongoDB and IPFS synchronously.

{
  strategy: 'write-through';
}

Pros:

  • Guaranteed consistency
  • Data always in sync

Cons:

  • Slower writes (waits for IPFS)

Use when: Data consistency is critical

Write-Behind

Writes to MongoDB immediately, queues IPFS async.

{
  strategy: 'write-behind';
}

Pros:

  • Fast writes
  • No user-facing latency

Cons:

  • Eventual consistency
  • Requires queue infrastructure

Use when: Performance is critical

Read-Through

Reads from MongoDB first, falls back to IPFS.

{
  strategy: 'read-through';
}

Pros:

  • Always returns data
  • IPFS as backup

Cons:

  • IPFS is secondary

Use when: MongoDB is primary, IPFS is backup

None

No automatic sync - you handle it manually.

{
  strategy: 'none';
}

📝 Usage Examples

Basic CRUD

// CREATE - Automatically synced to IPFS
const user = await User.create({
  name: 'Bob',
  email: '[email protected]'
});
console.log(user._id); // MongoDB ID

// READ - Query from MongoDB as usual
const users = await User.find({ age: { $gte: 18 } });

// UPDATE - Synced to IPFS
await User.findByIdAndUpdate(user._id, { age: 30 });

// DELETE - Removed from IPFS too
await User.findByIdAndDelete(user._id);

Bulk Operations

// Insert many - Each synced to IPFS
await User.insertMany([
  { name: 'Alice', email: '[email protected]' },
  { name: 'Charlie', email: '[email protected]' }
]);

// Update many - Each updated on IPFS
await User.updateMany({ age: { $lt: 18 } }, { status: 'minor' });

// Delete many
await User.deleteMany({ status: 'inactive' });

Instance Methods

// Save instance - Synced to IPFS
const user = new User({ name: 'David', email: '[email protected]' });
await user.save();

// Modify and save - Update synced to IPFS
user.age = 35;
await user.save();

// Remove instance - Removed from IPFS
await user.remove();

Query from IPFS

// Query MongoDB normally
const user = await User.findOne({ email: '[email protected]' });

// Also query directly from IPFS via PinatinoDB
const userCollection = pinatino.getCollection('user'); // lowercase model name
if (userCollection) {
  const ipfsUsers = await userCollection.findAll();
  console.log(`${ipfsUsers.length} users on IPFS`);

  ipfsUsers.forEach(u => {
    console.log(`${u.name} - CID: ${u._cid}`);
  });
}

🎨 Advanced Patterns

Hybrid Storage

Store different data in different places:

// Public profiles → IPFS (permanent, censorship-resistant)
const UserProfile = withPinatino(mongoose.model('UserProfile', ProfileSchema), {
  pinatino,
  logging: true
});

// Private data → MongoDB only (not wrapped)
const UserAuth = mongoose.model('UserAuth', AuthSchema);

// Temporary data → MongoDB only
const Session = mongoose.model('Session', SessionSchema);

Custom Error Handling

import * as Sentry from '@sentry/node';

const User = withPinatino(mongoose.model('User', UserSchema), {
  pinatino,
  onError: (error, operation, model) => {
    // Log to error tracking
    Sentry.captureException(error, {
      tags: { model, operation, adapter: 'mongoose' }
    });

    // Custom recovery logic
    if (operation === 'save') {
      // Maybe retry or queue for later
    }
  }
});

Environment-Based Config

const isDev = process.env.NODE_ENV === 'development';

const User = withPinatino(mongoose.model('User', UserSchema), {
  pinatino,
  strategy: isDev ? 'none' : 'write-through',
  logging: isDev
});

🔍 Querying

MongoDB (Fast)

// Query from MongoDB - fast, indexed
const users = await User.find({ age: { $gte: 18 } })
  .sort({ createdAt: -1 })
  .limit(10);

IPFS (Decentralized)

// Query from IPFS - decentralized, permanent
const userCollection = pinatino.getCollection('user');
const ipfsUsers = await userCollection.find().where('age', '>=', 18).limit(10).exec();

Hybrid Approach

// Try MongoDB first, fallback to IPFS
async function getUser(id: string) {
  try {
    // Fast path: MongoDB
    return await User.findById(id);
  } catch (error) {
    // Fallback: IPFS
    const collection = pinatino.getCollection('user');
    return await collection.findById(id);
  }
}

🚨 Error Handling

The adapter handles errors gracefully:

const User = withPinatino(mongoose.model('User', UserSchema), {
  pinatino,
  logging: true,
  onError: (error, operation, model) => {
    console.error(`IPFS sync failed for ${model}.${operation}`);
    // MongoDB operation succeeds even if IPFS fails
    // Your app continues working
  }
});

🎯 Best Practices

1. Selective Sync

Don't sync everything:

// ✅ Good - Only public, permanent data
const User = withPinatino(UserModel, { pinatino, models: ['User', 'Post'] });

// ❌ Bad - Syncing temporary data
const Session = withPinatino(SessionModel, { pinatino }); // Don't do this

2. Use Appropriate Strategy

// User profiles - write-through (consistency matters)
const User = withPinatino(UserModel, { pinatino, strategy: 'write-through' });

// Analytics - write-behind (performance matters)
const Event = withPinatino(EventModel, { pinatino, strategy: 'write-behind' });

3. Monitor IPFS Sync

const User = withPinatino(UserModel, {
  pinatino,
  logging: process.env.NODE_ENV === 'development',
  onError: error => {
    metrics.increment('ipfs.sync.errors');
    // Alert on production errors
  }
});

4. Handle ObjectId Conversion

// MongoDB uses ObjectId, IPFS uses string IDs
const doc = await User.findById(mongoId);
const ipfsId = doc._id.toString(); // Convert for IPFS queries

📊 Performance

MongoDB vs IPFS

| Operation | MongoDB | IPFS | Recommendation | | -------------- | ------- | ------------ | ----------------- | | Write | ~1ms | ~50ms | Use write-behind | | Read | ~1ms | ~20ms | Read from MongoDB | | Query | ~5ms | ~50ms | Use MongoDB | | Permanence | Mutable | ✅ Immutable | IPFS for archives |

Optimization Tips

// Batch operations
await User.insertMany(records); // Better than individual saves

// Use lean() for read-only queries
const users = await User.find().lean(); // Faster, no Mongoose docs

// Index frequently queried fields
UserSchema.index({ email: 1 });
UserSchema.index({ createdAt: -1 });

🔗 Integration with PinatinoDB

Direct PinatinoDB Queries

// Access the underlying PinatinoDB collection
const userCollection = pinatino.getCollection('user');

// Time-travel queries (IPFS immutability)
const history = await userCollection.history(userId);

// Query by CID
const oldVersion = await userCollection.findByCid('bafybe...');

🧪 Testing

// Use 'none' strategy in tests
const User = withPinatino(UserModel, {
  pinatino,
  strategy: 'none' // No IPFS calls during tests
});

📚 More Examples

Check out the complete working example for a full implementation.

🤝 Contributing

Found a bug or have a feature request? Open an issue!

📄 License

MIT


Made with ❤️ for MongoDB + Web3 developers