afridho-mongodb
Version:
A simple MongoDB client wrapper for easy database operations
377 lines (376 loc) • 13.5 kB
TypeScript
import { MongoClient, Document, ObjectId } from "mongodb";
declare global {
var _mongoClient: MongoClient | undefined;
}
interface ReadAllOptions {
/**
* Optional sort object, e.g. { createdAt: 1 } for ascending or { createdAt: -1 } for descending
*/
sort?: Document;
limit?: number;
skip?: number;
}
/**
* Class representing a MongoDB client for a specific collection.
*/
declare class ClientDB {
/**
* Returns the native MongoDB Db instance from the global connection.
* Useful for libraries that require a direct Db object (e.g. Better-Auth).
*/
static getNativeDb(): Promise<import("mongodb").Db>;
/**
* Returns the native MongoDB Db instance for this instance's connection.
*/
getNativeDb(): Promise<import("mongodb").Db>;
/**
* Returns the native MongoDB Db instance synchronously.
* The driver will handle connection queuing in the background.
*/
static getNativeDbSync(): import("mongodb").Db;
private client;
private collectionName;
private collection;
/**
* Creates an instance of ClientDB.
* @param {string} collectionName - The name of the collection to interact with.
*/
constructor(collectionName: string);
/**
* Connects to the MongoDB database and initializes the collection.
* @returns {Promise<void>}
*/
connect(): Promise<void>;
/**
* Helper to convert _id string to ObjectId if needed
* @param {Document} query - The query object to preprocess
* @returns {Document} The processed query with _id converted if applicable
*/
private preprocessQuery;
/**
* Reads a document from the collection based on the provided query.
* @param {Document} query - The query to find the document.
* @returns {Promise<Document|null>} The found document or null if not found.
*/
read(query: Document): Promise<Document | null>;
/**
* Reads all documents from the collection with optional sorting.
* @param {ReadAllOptions} [options] - Optional options object.
* @param {Document} [options.sort] - Optional sort object, e.g. { createdAt: 1 } for ascending.
* @returns {Promise<Document[]>} An array of all documents, optionally sorted.
*/
readAll(options?: ReadAllOptions): Promise<Document[]>;
/**
* Inserts a new document into the collection.
* @param {Document} data - The data to insert.
* @returns {Promise<Document>} The result of the insert operation.
*/
insert(data: Document): Promise<Document>;
/**
* Inserts multiple documents into the collection.
* @param {Document[]} data - The data to insert.
* @returns {Promise<Document>} The result of the insert operation.
*/
insertMany(data: Document[]): Promise<Document>;
/**
* Updates a document in the collection based on the provided query.
* @param {Document} query - The query to find the document to update.
* @param {Document} data - The data to update.
* @returns {Promise<Document>} The result of the update operation.
*/
update(query: Document, data: Document): Promise<Document>;
/**
* Updates multiple documents in the collection.
* - If you pass Mongo operators ($set, $inc, etc), it will use them directly.
* - If you pass a plain object, it will wrap it inside $set.
*
* @param {Document} query - The filter to match documents.
* @param {Document} data - The update data (plain object or with operators).
* @returns {Promise<Document>} The result of the update operation.
*/
updateMany(query: Document, data: Document | Document[], options?: {
upsert?: boolean;
}): Promise<Document>;
/**
* Deletes a document from the collection based on the provided query.
* @param {Document} query - The query to find the document to delete.
* @returns {Promise<Document>} The result of the delete operation.
*/
delete(query: Document): Promise<Document>;
/**
* Deletes multiple documents from the collection based on the provided query.
* @param {Document} query - The query to find the documents to delete.
* @returns {Promise<Document>} The result of the delete operation.
*/
deleteMany(query: Document): Promise<Document>;
/**
* Finds multiple documents in the collection based on the provided query.
* @param {Document} query - The query to find the documents.
* @returns {Promise<Document[]>} An array of found documents.
*/
find(query: Document, options?: ReadAllOptions, project?: Document): Promise<Document[]>;
/**
* Reads multiple documents from the collection based on a query.
* @param {Document} query - The filter query.
* @returns {Promise<Document[]>} Array of matching documents.
*/
readMany(query: Document): Promise<Document[]>;
/**
* Gets random documents from the collection.
* @param {number} [total=1] - The number of random documents to retrieve.
* @returns {Promise<Document[]>} An array of random documents.
*/
getRandomData(total?: number): Promise<Document[]>;
/**
* Run an aggregation pipeline on the current collection.
*
* @param {Array<Document>} pipeline - An array of MongoDB aggregation stages.
* Example:
* [
* { $unwind: "$tags" },
* { $group: { _id: "$tags", count: { $sum: 1 } } },
* { $sort: { count: -1 } },
* { $limit: 10 }
* ]
*
* @returns {Promise<Document[]>} Resolves with the array of aggregation results.
*
* @throws {Error} If the aggregation query fails.
*/
aggregate(pipeline?: Document[]): Promise<Document[]>;
/**
* Gets the storage statistics for the collection.
* @returns {Promise<{storageSize: number, size: number, count: number}>} The storage statistics including storageSize.
*/
getStorageStats(): Promise<{
storageSize: number;
size: number;
count: number;
}>;
/**
* Gets cluster-wide storage statistics.
*/
static getClusterStats(): Promise<{
totalDataSize: number;
totalStorageSize: number;
totalIndexSize: number;
databases: any[];
}>;
/**
* Closes the MongoDB connection.
* @returns {Promise<void>}
*/
close(): Promise<void>;
/**
* Finds documents in the current collection and dynamically joins related collections
* using MongoDB's `$lookup` aggregation stage.
*
* This is useful when you want to "populate" data from other collections
* (similar to Mongoose's populate) but in a flexible, dynamic way.
*
* ### Example:
* ```ts
* const tasks = await tasksDb.findWithRelations(
* { column: "todo" }, // filter
* [
* {
* from: "kanban_tags",
* localField: "tags",
* foreignField: "value",
* as: "tags"
* },
* {
* from: "kanban_persons",
* localField: "persons",
* foreignField: "_id",
* as: "persons",
* isObjectId: true // convert string IDs to ObjectId
* }
* ],
* {
* title: 1,
* description: 1,
* "tags.label": 1,
* "persons.name": 1
* },
* {
* sort: { createdAt: -1 },
* limit: 10,
* skip: 20
* }
* );
* ```
*
* @param {Document} [filter={}] - MongoDB query filter. Defaults to `{}` (fetch all).
* @param {Object[]} [relations=[]] - Array of relation configurations for `$lookup`.
* @param {string} relations[].from - Target collection name to join with.
* @param {string} relations[].localField - Field in this collection that holds the reference.
* @param {string} relations[].foreignField - Field in the target collection to match against.
* @param {string} relations[].as - The alias name for the joined data in the output.
* @param {boolean} [relations[].isObjectId] - If `true`, will map string IDs in `localField` into ObjectId before lookup.
* @param {Document} [project={}] - Optional MongoDB projection object to limit fields in the final output.
* @param {ReadAllOptions} [options={}] - Optional settings like sort, skip, and limit.
*
* @returns {Promise<Document[]>} A promise that resolves to an array of documents with joined relations applied.
*/
findWithRelations(filter?: Document, relations?: {
from: string;
localField: string;
foreignField: string;
as: string;
isObjectId?: boolean;
isSingle?: boolean;
}[], project?: Document, options?: ReadAllOptions): Promise<Document[]>;
/**
* Finds a single document in the current collection and dynamically joins related collections
* using MongoDB's `$lookup` aggregation stage.
*
* Mirip dengan `findWithRelations`, tapi hanya return satu dokumen (bukan array).
*
* ### Example:
* ```ts
* const task = await tasksDb.findOneWithRelations(
* { _id: "66cfa89f3c9c7d776b5f4f10" },
* [
* {
* from: "kanban_tags",
* localField: "tags",
* foreignField: "value",
* as: "tags"
* },
* {
* from: "kanban_persons",
* localField: "persons",
* foreignField: "_id",
* as: "persons",
* isObjectId: true
* }
* ]
* );
* ```
*
* @param {Document} filter - MongoDB query filter. Biasanya pakai `_id`.
* @param {Object[]} [relations=[]] - Array of relation configs sama seperti `findWithRelations`.
* @param {Document} [project={}] - Projection untuk limit field output.
*
* @returns {Promise<Document | null>} A single document with joined relations, or `null`.
*/
findOneWithRelations(filter: Document, relations?: {
from: string;
localField: string;
foreignField: string;
as: string;
isObjectId?: boolean;
isSingle?: boolean;
}[], project?: Document): Promise<Document | null>;
/**
* Counts the number of documents matching the query.
* Alias for countDocuments.
* @param {Document} [query={}] - Optional filter query.
* @returns {Promise<number>} The count of matching documents.
*/
count(query?: Document): Promise<number>;
/**
* Counts the number of documents matching the query.
* @param {Document} [query={}] - Optional filter query.
* @returns {Promise<number>} The count of matching documents.
*/
countDocuments(query?: Document): Promise<number>;
/**
* One-time migration: convert string date fields to Date objects.
*
* @param fields - Which fields to convert (default: createdAt, updatedAt, startAt, endAt)
* @returns number of documents updated
*/
migrateDateFields(fields?: string[]): Promise<number>;
/**
* INTERNAL: Connect to external cluster
*/
private static _connectExternal;
/**
* INCREMENTAL BACKUP (NO DELETE):
* - Hanya ambil dokumen yang updatedAt > lastBackupAt
* - Tidak pernah hapus dokumen di backup
* - Upsert-only
*/
static incrementalBackupOneDatabase(params: {
targetUri: string;
sourceDb: string;
targetDb: string;
}): Promise<{
mode: string;
sourceDb: string;
targetDb: string;
lastBackupAt: Date;
executedAt: Date;
report: any[];
}>;
/**
* MULTI-DATABASE INCREMENTAL (NO DELETE)
*/
static incrementalBackupManyDatabases(targetUri: string, dbList: string[]): Promise<{
mode: string;
targetUri: string;
results: any[];
}>;
/**
* DELTA BACKUP (NO DELETE):
* - hanya dokumen baru (yang belum ada _id nya di backup)
* - tidak pernah hapus
*/
static deltaBackupOneDatabase(params: {
targetUri: string;
sourceDb: string;
targetDb: string;
}): Promise<{
mode: string;
sourceDb: string;
targetDb: string;
report: any[];
}>;
/**
* MULTI-DATABASE DELTA (NO DELETE)
*/
static deltaBackupManyDatabases(targetUri: string, dbList: string[]): Promise<{
mode: string;
targetUri: string;
results: any[];
}>;
static fullSyncOneDatabase(params: {
sourceUri: string;
targetUri: string;
dbName: string;
}): Promise<{
mode: string;
sourceDb: string;
snapshotDb: string;
inserted: number;
updated: number;
deleted: number;
report: any[];
}>;
static fullSyncManyDatabases(params: {
targetURI: string;
dbs: string[];
keepWeeks?: number;
}): Promise<{
mode: string;
syncedDatabases: string[];
results: PromiseSettledResult<{
mode: string;
sourceDb: string;
snapshotDb: string;
inserted: number;
updated: number;
deleted: number;
report: any[];
}>[];
}>;
static cleanupSnapshots(params: {
targetURI: string;
dbs: string[];
keepWeeks?: number;
}): Promise<void>;
}
export default ClientDB;
export { ObjectId };