Appearance
MongoDB
MongoDB backend for server deployments. Documents are rendered into collections named by type (e.g., bookmark, folder).
Setup
typescript
import { MongoClient } from 'mongodb';
import { DocumentStore, MongoDbPersistence } from 'document-store';
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const db = client.db('myapp');
const store = new DocumentStore({
storage: new MongoDbPersistence(db)
});
store.registerType('bookmark', {
render: { time: true, uid: true, updated: true }
});Collection structure
Each type gets a MongoDB collection. Documents are stored as regular BSON with Buffer fields preserved:
javascript
{
hash: Binary(Buffer), // always present
uid: Binary(Buffer), // if render.uid = true
time: 1710000000, // if render.time = true
updated: 1710001000, // if render.updated = true
url: "https://...", // app fields
title: "Example",
}Reading documents
Simple queries
typescript
const collection = db.collection('bookmark');
// All bookmarks
const all = await collection.find({}).toArray();
// By hash
const doc = await collection.findOne({ hash: someHash });
// Filter
const mine = await collection.find({ uid: myUid }).toArray();Sorting and pagination
typescript
const recent = await collection
.find({})
.sort({ updated: -1 })
.limit(20)
.toArray();
const page = await collection
.find({ uid: myUid })
.sort({ time: -1 })
.skip(pageSize * pageNum)
.limit(pageSize)
.toArray();Lookups across document types
Use $lookup (MongoDB's join) to resolve parent references:
typescript
const withFolders = await db.collection('bookmark').aggregate([
{
$lookup: {
from: 'folder',
localField: 'parent',
foreignField: 'hash',
as: 'folder'
}
},
{ $unwind: { path: '$folder', preserveNullAndEmptyArrays: true } },
{ $sort: { time: -1 } },
{ $limit: 50 },
]).toArray();Text search
typescript
// Create a text index
await collection.createIndex({ title: 'text', url: 'text' });
// Search
const results = await collection
.find({ $text: { $search: 'example' } })
.toArray();Aggregation
typescript
// Count by owner
const counts = await collection.aggregate([
{ $group: { _id: '$uid', count: { $sum: 1 } } },
]).toArray();
// Tag frequency
const tags = await collection.aggregate([
{ $unwind: '$tags' },
{ $group: { _id: '$tags', count: { $sum: 1 } } },
{ $sort: { count: -1 } },
]).toArray();Indexes
Create indexes for your query patterns:
typescript
await collection.createIndex({ updated: -1 });
await collection.createIndex({ uid: 1 });
await collection.createIndex({ parent: 1 });
await collection.createIndex({ uid: 1, updated: -1 }); // compound