update mongo for multi db support

This commit is contained in:
Boki 2025-06-14 12:19:20 -04:00
parent 4942574b94
commit cbef304045
7 changed files with 927 additions and 13 deletions

View file

@ -0,0 +1,216 @@
/**
* Example: Enhanced Data Service with Multi-Database Support
*
* This shows how to update your existing data service to leverage
* the new multi-database MongoDB client functionality.
*/
import { getLogger } from '@stock-bot/logger';
import { MongoDBClient, setDefaultDatabase } from '@stock-bot/mongodb-client';
const logger = getLogger('enhanced-data-service');
export class EnhancedDataService {
private mongoClient = MongoDBClient.getInstance();
async initialize() {
// Connect to MongoDB
await this.mongoClient.connect();
// Set stock as default database for market data operations
setDefaultDatabase('stock');
logger.info('Enhanced data service initialized with multi-database support');
}
/**
* Save Interactive Brokers data to stock database
*/
async saveIBMarketData(exchanges: any[], symbols: any[]) {
logger.info('Saving IB market data to stock database');
// These use the default 'stock' database
const exchangeResult = await this.mongoClient.batchUpsert(
'exchanges',
exchanges,
'exchange_id'
);
const symbolResult = await this.mongoClient.batchUpsert('symbols', symbols, 'symbol');
// Or use convenience method for cleaner code
// const exchangeResult = await this.mongoClient.batchUpsertStock('exchanges', exchanges, 'exchange_id');
// const symbolResult = await this.mongoClient.batchUpsertStock('symbols', symbols, 'symbol');
logger.info('IB market data saved', {
exchanges: exchangeResult,
symbols: symbolResult,
});
return { exchanges: exchangeResult, symbols: symbolResult };
}
/**
* Save real-time prices to stock database
*/
async saveRealTimePrices(priceData: any[]) {
logger.info(`Saving ${priceData.length} real-time prices to stock database`);
return await this.mongoClient.batchUpsertStock('real_time_prices', priceData, [
'symbol',
'timestamp',
]);
}
/**
* Save performance analytics to analytics database
*/
async savePerformanceAnalytics(performanceData: any[]) {
logger.info(`Saving ${performanceData.length} performance records to analytics database`);
return await this.mongoClient.batchUpsertAnalytics('performance_metrics', performanceData, [
'portfolio_id',
'date',
]);
}
/**
* Save trading logs to trading_documents database
*/
async saveTradingLogs(logs: any[]) {
logger.info(`Saving ${logs.length} trading logs to trading_documents database`);
return await this.mongoClient.batchUpsertTrading('trading_logs', logs, 'log_id');
}
/**
* Example: Cross-database analytics
*/
async generateCrossDatabaseReport() {
logger.info('Generating cross-database analytics report');
// Get data from multiple databases
const stockDb = this.mongoClient.getDatabase('stock');
const analyticsDb = this.mongoClient.getDatabase('analytics');
const tradingDb = this.mongoClient.getDatabase('trading_documents');
// Get counts from different databases
const symbolCount = await stockDb.collection('symbols').countDocuments();
const exchangeCount = await stockDb.collection('exchanges').countDocuments();
const performanceCount = await analyticsDb.collection('performance_metrics').countDocuments();
const logCount = await tradingDb.collection('trading_logs').countDocuments();
const report = {
stock_database: {
symbols: symbolCount,
exchanges: exchangeCount,
},
analytics_database: {
performance_metrics: performanceCount,
},
trading_database: {
logs: logCount,
},
generated_at: new Date(),
};
logger.info('Cross-database report generated', report);
return report;
}
/**
* Example: Database-specific operations
*/
async performDatabaseSpecificOperations() {
// Switch default database for a series of analytics operations
const originalDefault = this.mongoClient.getDefaultDatabase();
this.mongoClient.setDefaultDatabase('analytics');
try {
// Now all operations without explicit database go to 'analytics'
await this.mongoClient.batchUpsert('daily_reports', [], 'date');
await this.mongoClient.batchUpsert('portfolio_summaries', [], 'portfolio_id');
logger.info('Analytics operations completed on analytics database');
} finally {
// Restore original default database
this.mongoClient.setDefaultDatabase(originalDefault);
}
}
/**
* Example: Configuration-driven database routing
*/
async saveDataByType(dataType: string, collection: string, data: any[], uniqueKeys: string[]) {
const databaseMapping: Record<string, string> = {
market_data: 'stock',
analytics: 'analytics',
trading: 'trading_documents',
logs: 'trading_documents',
};
const targetDatabase = databaseMapping[dataType] || 'stock';
logger.info(`Saving ${data.length} records`, {
dataType,
targetDatabase,
collection,
});
return await this.mongoClient.batchUpsert(collection, data, uniqueKeys, {
database: targetDatabase,
});
}
async shutdown() {
logger.info('Shutting down enhanced data service');
await this.mongoClient.disconnect();
}
}
// Usage example for your existing data service
export async function integrateWithExistingDataService() {
const enhancedService = new EnhancedDataService();
try {
await enhancedService.initialize();
// Example market data
const exchanges = [
{ exchange_id: 'NYSE', name: 'New York Stock Exchange', mic: 'XNYS' },
{ exchange_id: 'NASDAQ', name: 'NASDAQ', mic: 'XNAS' },
];
const symbols = [
{ symbol: 'AAPL', exchange: 'NASDAQ', company_name: 'Apple Inc.' },
{ symbol: 'MSFT', exchange: 'NASDAQ', company_name: 'Microsoft Corporation' },
];
// Save to appropriate databases
await enhancedService.saveIBMarketData(exchanges, symbols);
// Save real-time prices
await enhancedService.saveRealTimePrices([
{ symbol: 'AAPL', price: 150.25, volume: 1000000, timestamp: new Date() },
]);
// Save analytics
await enhancedService.savePerformanceAnalytics([
{ portfolio_id: 'portfolio_1', date: new Date(), return: 0.15 },
]);
// Generate cross-database report
const report = await enhancedService.generateCrossDatabaseReport();
console.log('Cross-database report:', report);
// Example of configuration-driven routing
await enhancedService.saveDataByType('market_data', 'prices', [], 'symbol');
await enhancedService.saveDataByType('analytics', 'metrics', [], 'metric_id');
} catch (error) {
logger.error('Enhanced data service error:', error);
} finally {
await enhancedService.shutdown();
}
}
// Export for integration
export default EnhancedDataService;

View file

@ -0,0 +1,230 @@
/**
* Practical Usage Examples for Multi-Database MongoDB Client
*
* This file demonstrates real-world usage patterns for the enhanced MongoDB client
* with multiple database support.
*/
import { getCurrentDatabase, MongoDBClient, setDefaultDatabase } from '@stock-bot/mongodb-client';
// Example 1: Using different databases for different data types
export class DataServiceExample {
private mongoClient = MongoDBClient.getInstance();
async initialize() {
await this.mongoClient.connect();
// Set stock as default database for most operations
setDefaultDatabase('stock');
console.log(`Default database: ${getCurrentDatabase()}`);
}
// Stock market data goes to 'stock' database (default)
async saveStockData(symbols: any[], exchanges: any[]) {
// These use the default 'stock' database
await this.mongoClient.batchUpsert('symbols', symbols, 'symbol');
await this.mongoClient.batchUpsert('exchanges', exchanges, 'exchange_id');
// Or use convenience method (explicitly targets 'stock' database)
await this.mongoClient.batchUpsertStock('prices', symbols, 'symbol');
}
// Analytics and metrics go to 'analytics' database
async saveAnalyticsData(performanceData: any[], metrics: any[]) {
// Override database for specific operations
await this.mongoClient.batchUpsert('performance', performanceData, 'date', {
database: 'analytics',
});
// Or use convenience method
await this.mongoClient.batchUpsertAnalytics('metrics', metrics, 'metric_name');
}
// Trading documents and logs go to 'trading_documents' database
async saveTradingData(orders: any[], transactions: any[]) {
// Use convenience method for trading data
await this.mongoClient.batchUpsertTrading('orders', orders, 'order_id');
await this.mongoClient.batchUpsertTrading('transactions', transactions, 'transaction_id');
}
// Example of switching default database dynamically
async switchToAnalyticsMode() {
console.log(`Current default: ${getCurrentDatabase()}`);
// Switch to analytics database for a series of operations
setDefaultDatabase('analytics');
console.log(`New default: ${getCurrentDatabase()}`);
// Now all operations without explicit database parameter go to 'analytics'
await this.mongoClient.batchUpsert('daily_reports', [], 'date');
await this.mongoClient.batchUpsert('portfolio_performance', [], 'portfolio_id');
// Switch back to stock database
setDefaultDatabase('stock');
}
// Example of working with multiple databases simultaneously
async crossDatabaseAnalysis() {
// Get direct access to different databases
const stockDb = this.mongoClient.getDatabase('stock');
const analyticsDb = this.mongoClient.getDatabase('analytics');
const tradingDb = this.mongoClient.getDatabase('trading_documents');
// Perform operations on multiple databases
const stockSymbols = await stockDb.collection('symbols').find({}).toArray();
const performance = await analyticsDb.collection('performance').find({}).toArray();
const orders = await tradingDb.collection('orders').find({}).toArray();
console.log('Cross-database analysis:', {
symbolsCount: stockSymbols.length,
performanceRecords: performance.length,
ordersCount: orders.length,
});
}
}
// Example 2: Data Migration Between Databases
export class DataMigrationExample {
private mongoClient = MongoDBClient.getInstance();
async migrateHistoricalData() {
await this.mongoClient.connect();
// Get collections from different databases
const stockCollection = this.mongoClient.getCollection('historical_prices', 'stock');
const analyticsCollection = this.mongoClient.getCollection('price_analysis', 'analytics');
// Read from stock database
const historicalPrices = await stockCollection
.find({
date: { $gte: new Date('2024-01-01') },
})
.toArray();
console.log(`Found ${historicalPrices.length} historical price records`);
// Transform and save to analytics database
const analysisData = historicalPrices.map(price => ({
symbol: price.symbol,
date: price.date,
price_change: price.close - price.open,
volume_normalized: price.volume / 1000000,
created_at: new Date(),
updated_at: new Date(),
}));
// Save to analytics database
await this.mongoClient.batchUpsert('price_analysis', analysisData, ['symbol', 'date'], {
database: 'analytics',
});
console.log(`Migrated ${analysisData.length} records to analytics database`);
}
}
// Example 3: Service-Specific Database Usage
export class TradingServiceExample {
private mongoClient = MongoDBClient.getInstance();
async initialize() {
await this.mongoClient.connect();
// Trading service primarily works with trading_documents database
setDefaultDatabase('trading_documents');
}
async processTradeOrders(orders: any[]) {
// Default database is 'trading_documents', so no need to specify
await this.mongoClient.batchUpsert('orders', orders, 'order_id');
// Log to analytics database for monitoring
const orderMetrics = orders.map(order => ({
metric_name: `order_${order.type}`,
value: order.quantity,
timestamp: new Date(),
}));
await this.mongoClient.batchUpsert(
'trading_metrics',
orderMetrics,
['metric_name', 'timestamp'],
{ database: 'analytics' }
);
}
async getOrderHistory(symbolFilter?: string) {
// Get collection from default database (trading_documents)
const ordersCollection = this.mongoClient.getCollection('orders');
const filter = symbolFilter ? { symbol: symbolFilter } : {};
return await ordersCollection.find(filter).sort({ created_at: -1 }).limit(100).toArray();
}
}
// Example 4: Configuration-Based Database Routing
export class ConfigurableDatabaseRouter {
private mongoClient = MongoDBClient.getInstance();
// Configuration mapping data types to databases
private databaseConfig = {
market_data: 'stock',
user_data: 'trading_documents',
analytics: 'analytics',
logs: 'trading_documents',
cache: 'analytics',
};
async saveData(
dataType: keyof typeof this.databaseConfig,
collection: string,
data: any[],
uniqueKeys: string[]
) {
const targetDatabase = this.databaseConfig[dataType];
console.log(`Saving ${data.length} records to ${targetDatabase}.${collection}`);
return await this.mongoClient.batchUpsert(collection, data, uniqueKeys, {
database: targetDatabase,
});
}
async saveMarketData(data: any[]) {
return this.saveData('market_data', 'realtime_prices', data, 'symbol');
}
async saveUserActivity(data: any[]) {
return this.saveData('user_data', 'user_actions', data, 'user_id');
}
async saveAnalytics(data: any[]) {
return this.saveData('analytics', 'performance_metrics', data, 'metric_id');
}
}
// Usage example for your data service
export async function exampleUsage() {
const dataService = new DataServiceExample();
await dataService.initialize();
// Save different types of data to appropriate databases
await dataService.saveStockData(
[{ symbol: 'AAPL', price: 150.25, volume: 1000000 }],
[{ exchange_id: 'NYSE', name: 'New York Stock Exchange' }]
);
await dataService.saveAnalyticsData(
[{ date: new Date(), portfolio_return: 0.15 }],
[{ metric_name: 'sharpe_ratio', value: 1.25 }]
);
await dataService.saveTradingData(
[{ order_id: 'ORD001', symbol: 'AAPL', quantity: 100 }],
[{ transaction_id: 'TXN001', amount: 15025 }]
);
// Perform cross-database analysis
await dataService.crossDatabaseAnalysis();
console.log('Multi-database operations completed successfully!');
}