@fjell/lib-firestore
v4.4.76
Published
Firestore Library for Fjell
Downloads
3,041
Maintainers
Readme
@fjell/lib-firestore
Firestore integration for the Fjell ecosystem providing NoSQL database implementations for Google Cloud Firestore.
New Architecture (v4.4.12+)
This library now uses the new FirestoreLibrary architecture that extends @fjell/lib:
fjell-registry.Instance
↓ extends
fjell-lib.Library
↓ extends
fjell-lib-firestore.FirestoreLibraryInstallation
npm install @fjell/lib-firestore @fjell/lib @fjell/registry firebase-adminQuick Start
New FirestoreLibrary API (v4.4.12+)
import { createRegistry } from '@fjell/registry';
import { createFirestoreLibrary, FirestoreLibrary } from '@fjell/lib-firestore';
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
// Initialize Firestore
const app = initializeApp();
const firestore = getFirestore(app);
// Create a FirestoreLibrary
const userLibrary: FirestoreLibrary<UserItem, 'user'> = createFirestoreLibrary(
['user'], // Key type array
['users'], // Collection names
firestore,
{
validators: {
email: (email) => email.includes('@')
},
hooks: {
beforeCreate: async (user) => {
user.createdAt = new Date();
return user;
}
}
},
[], // Scopes
registry
);
// Use the library
const users = await userLibrary.operations.all({});
const newUser = await userLibrary.operations.create({
name: 'Alice Johnson',
email: '[email protected]'
});
// Access Firestore-specific features
console.log('Firestore project:', userLibrary.firestore.projectId);Features
FirestoreLibrary Extends Library
The FirestoreLibrary interface adds:
- firestore: Firestore database instance
- All Library features: operations, options, coordinate, registry
interface FirestoreLibrary<T, S> extends Library<T, S> {
firestore: FirebaseFirestore.Firestore;
}NoSQL Operations
Built-in operations automatically use Firestore collections:
// CRUD operations use Firestore under the hood
await userLibrary.operations.create(userData);
await userLibrary.operations.find({ filter: { email: '[email protected]' } });
await userLibrary.operations.update(['user-123'], { name: 'Alice Smith' });
await userLibrary.operations.remove(['user-123']);
// Advanced queries with Firestore features
await userLibrary.operations.all({
filter: {
status: 'active',
createdAt: { '>=': new Date('2024-01-01') }
},
sort: { createdAt: 'desc' },
limit: 10
});Collection Integration
Your Firestore collections are automatically managed:
// Create FirestoreLibrary with collection configuration
const userLibrary = createFirestoreLibrary(
['user'],
['users'], // Collection name in Firestore
firestore,
options
);
// Operations automatically use the 'users' collection
const users = await userLibrary.operations.all({}); // Query users collectionAdvanced Usage
Multiple Collections
// User library with multiple related collections
const userLibrary = createFirestoreLibrary(
['user'],
['users', 'user_profiles', 'user_settings'], // Multiple collections
firestore,
{
hooks: {
afterCreate: async (user) => {
// Automatically create profile and settings documents
await firestore.collection('user_profiles').doc(user.id).set({
userId: user.id,
displayName: user.name
});
await firestore.collection('user_settings').doc(user.id).set({
userId: user.id,
theme: 'light'
});
}
}
}
);Custom Operations
import { createOperations } from '@fjell/lib-firestore';
const customOperations = createOperations(firestore, definition, registry, {
// Custom business logic
actions: {
activate: async (keys, params) => {
const userRef = firestore.collection('users').doc(keys[0]);
await userRef.update({
status: 'active',
activatedAt: admin.firestore.FieldValue.serverTimestamp()
});
return { success: true };
}
},
// Custom analytics using Firestore aggregation
facets: {
userStats: async (query, options) => {
const snapshot = await firestore.collection('users').get();
const users = snapshot.docs.map(doc => doc.data());
return {
total: users.length,
active: users.filter(u => u.status === 'active').length,
byRegion: groupBy(users, 'region')
};
}
}
});Hierarchical Data with Subcollections
Support for contained items with Firestore subcollections:
// Order library with location hierarchy
const orderItemLibrary = createFirestoreLibrary(
['orderItem', 'order', 'customer'], // Nested hierarchy
['customers/{customerId}/orders/{orderId}/items'], // Subcollection path
firestore,
options
);
// Query order items with location context
const orderItems = await orderItemLibrary.operations.all({}, ['order-123', 'customer-456']);Real-time Updates
Firestore real-time capabilities:
// Set up real-time listener (custom implementation)
const unsubscribe = firestore
.collection('users')
.where('status', '==', 'active')
.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'added') {
console.log('New user:', change.doc.data());
}
});
});Migration Guide
From v4.4.11 and earlier
- No breaking changes - existing code continues to work
- Optional migration to new naming:
// Clean Library architecture
import { createFirestoreLibrary, FirestoreLibrary } from '@fjell/lib-firestore';- Benefits of the new architecture:
- Clear naming that shows inheritance hierarchy
- Better TypeScript autocomplete and documentation
- Future-proof as the ecosystem evolves
Simple Setup
Use the FirestoreLibrary for all new development:
// Clean, consistent API
const userLibrary = createFirestoreLibrary(kta, collections, firestore, options);
const orderLibrary = createFirestoreLibrary(orderKta, orderCollections, firestore, orderOptions);Architecture Benefits
- Clear Inheritance: Shows how FirestoreLibrary extends Library
- Type Safety: Full TypeScript support throughout the hierarchy
- NoSQL Focus: FirestoreLibrary is clearly Firestore-specific
- Real-time Ready: Built for Firestore's real-time capabilities
- Clean API: Consistent naming and patterns across all libraries
Firestore-Specific Features
Document References
// Working with document references
const userRef = firestore.collection('users').doc('user-123');
const user = await userLibrary.operations.get(['user-123']);
// Batch operations
const batch = firestore.batch();
batch.set(userRef, userData);
batch.update(profileRef, profileData);
await batch.commit();Transactions
// Firestore transactions
await firestore.runTransaction(async (transaction) => {
const userDoc = await transaction.get(userRef);
if (userDoc.exists) {
transaction.update(userRef, { lastLogin: new Date() });
}
});Security Rules Integration
// Design your data model to work with Firestore security rules
const orderLibrary = createFirestoreLibrary(
['order'],
['orders'],
firestore,
{
// Operations automatically include user context for security rules
hooks: {
beforeCreate: async (order) => {
order.ownerId = getCurrentUserId(); // For security rules
return order;
}
}
}
);Examples
See the examples/ directory for complete working examples:
- Basic Firestore integration
- Real-time data sync
- Subcollection management
- Security rules patterns
TypeScript Support
Full TypeScript support with proper type inference:
import { Item } from '@fjell/core';
interface User extends Item<'user'> {
id: string;
name: string;
email: string;
status: 'active' | 'inactive';
}
const userLibrary: FirestoreLibrary<User, 'user'> = createFirestoreLibrary(
['user'],
['users'],
firestore,
options
);
// Full type safety
const user: User = await userLibrary.operations.create({
name: 'Alice',
email: '[email protected]',
status: 'active'
});Performance Considerations
Indexing
// Design operations with Firestore indexing in mind
await userLibrary.operations.find({
filter: {
status: 'active', // Simple field index
region: 'us-west', // Composite index needed
createdAt: { '>=': date } // for this combination
}
});Pagination
// Efficient pagination with Firestore cursors
let lastDoc = null;
const pageSize = 20;
const getNextPage = async () => {
const query = lastDoc
? firestore.collection('users').startAfter(lastDoc).limit(pageSize)
: firestore.collection('users').limit(pageSize);
const snapshot = await query.get();
lastDoc = snapshot.docs[snapshot.docs.length - 1];
return snapshot.docs.map(doc => doc.data());
};Next Steps
- Check out
@fjell/lib-sequelizefor SQL database integration - See
@fjell/libfor core Library functionality - Read
@fjell/registryfor base coordination features - Review Firestore documentation for advanced features
