为 zangodb 实现更多集合操作扩展

39 阅读4分钟

zangodb 是一个非常强大的 indexeddb 包装器,其实现里 mongodb 的众多语法和概念,让开发者在浏览器端也可以使用 mongodb 的语法,熟悉 mongo 的同学用起来可以说是如鱼得水,非常熟悉的感觉,但是总有不足之处,比如:zangodb 在实现 Collection 的 api 时 ,仅实现里最基础的几个 api,如下:  erikolson186.github.io/zangodb/Col…

由此可见,使用起来还是非常的不方便,我通过外部包装的方式增加了 updateOrInsertByIdsumcountmax 等扩展,这些都是常用的 api, 但写起来还是相当麻烦的。

扩展类封装

这里没有使用继承的方式,也是有一定原因的,暂不赘述。

// CollectionDcc.ts
import { Callback, Collection, Cursor } from "@insertish/zangodb";

export default class CollectionDcc {
    private _collection: Collection;

    /**
     * 创建一个 CollectionDcc 实例。
     * @param collection ZangoDB 的 Collection 对象。
     */
    constructor(collection: Collection) {
        this._collection = collection;
    }

    /**
     * 执行聚合操作并返回一个游标。
     * @param pipeline 聚合管道操作数组。
     * @returns 返回执行聚合操作后的游标对象。
     */
    public aggregate(pipeline: Object[]): Cursor {
        return this._collection.aggregate(pipeline);
    }

    /**
     * 更新匹配指定条件的文档。
     * @param expr 更新的查询条件。
     * @param spec 更新的字段和值。
     * @param cb 回调函数,在更新完成后调用。
     * @returns 返回一个 Promise,在更新完成后解析为 void。
     */
    public update(expr: Object, spec: Object, cb?: Callback): Promise<void> {
        return this._collection.update(expr, spec, cb);
    }

    /**
     * 插入一个或多个文档。
     * @param docs 要插入的文档对象或文档对象数组。
     * @param cb 回调函数,在插入完成后调用。
     * @returns 返回一个 Promise,在插入完成后解析为 void。
     */
    public insert(docs: Object | Object[], cb?: Callback): Promise<void> {
        return this._collection.insert(docs, cb);
    }

    /**
     * 删除匹配指定条件的文档。
     * @param expr 删除的查询条件。
     * @param cb 回调函数,在删除完成后调用。
     * @returns 返回一个 Promise,在删除完成后解析为 void。
     */
    public remove(expr: Object, cb?: Callback): Promise<void> {
        return this._collection.remove(expr, cb);
    }

    /**
     * 查找匹配指定条件的文档并返回一个游标。
     * @param expr 查询的条件。
     * @param projection_spec 投影操作,指定要返回的字段。
     * @returns 返回执行查询操作后的游标对象。
     */
    public find(expr: Object, projection_spec: Object): Cursor {
        return this._collection.find(expr, projection_spec);
    }

    /**
     * 查找并返回匹配指定条件的单个文档。
     * @param expr 查询的条件。
     * @param projection_spec 投影操作,指定要返回的字段。
     * @param cb 回调函数,在查询完成后调用。
     * @returns 返回一个 Promise,在查询完成后解析为查询到的文档对象。
     */
    public findOne(expr: Object, projection_spec: Object = {}, cb?: Callback): Promise<Object> {
        return this._collection.findOne(expr, projection_spec, cb);
    }

    /**
     * 根据指定的条件更新或插入文档。
     * 如果指定条件的文档不存在,则插入新文档;如果文档存在,则更新文档。
     * @param spec 更新或插入的文档。
     * @returns 返回一个 Promise,在更新或插入完成后解析为 void。
     */
    public updateOrInsertById(spec: Object): Promise<void> {
        return new Promise<void>((resolve, reject) => {
            this.count({ _id: spec["_id"] }).then((count) => {
                if (count === 0) {
                    this.insert(spec).then(() => {
                        resolve();
                    }).catch((err) => {
                        reject(err);
                    });
                } else {
                    this._collection.update({ _id: spec["_id"] }, spec).then(() => {
                        resolve();
                    }).catch((err) => {
                        reject(err);
                    });
                }
            }).catch((err) => {
                reject(err);
            });
        });
    }

    /**
     * 计算满足指定条件的文档字段的总和。
     * @param expr 指定计算总和的字段和条件。
     * @returns 返回一个 Promise,在计算完成后解析为总和值。
     */
    public sum(expr: Object): Promise<number> {
        return new Promise<number>((resolve, reject) => {
            this._collection.aggregate([
                { $match: expr },
                { $group: { _id: null, sum: { $sum: "$value" } } }
            ]).toArray((err, res) => {
                if (err) {
                    reject(err);
                } else {
                    const result = res.length === 0 ? { sum: 0 } : res[0] as { sum: number };
                    resolve(result.sum);
                }
            });
        });
    }

    /**
     * 计算满足指定条件的文档数量。
     * @param expr 指定计算数量的条件。
     * @returns 返回一个 Promise,在计算完成后解析为文档数量。
     */
    public count(expr: Object): Promise<number> {
        return new Promise<number>((resolve, reject) => {
            this._collection.aggregate([
                { $match: expr },
                { $group: { _id: null, count: { $sum: 1 } } }
            ]).toArray((err, res) => {
                if (err) {
                    reject(err);
                } else {
                    const result = res.length === 0 ? { count: 0 } : res[0] as { count: number };
                    resolve(result.count);
                }
            });
        });
    }

    /**
     * 计算满足指定条件的文档字段的最大值。
     * @param expr 指定计算最大值的字段和条件。
     * @returns 返回一个 Promise,在计算完成后解析为最大值。
     */
    public max(expr: Object): Promise<number> {
        return new Promise<number>((resolve, reject) => {
            this._collection.aggregate([
                { $match: expr },
                { $group: { _id: null, max: { $max: "$value" } } }
            ]).toArray((err, res) => {
                if (err) {
                    reject(err);
                } else {
                    const result = res.length === 0 ? { max: 0 } : res[0] as { max: number };
                    resolve(result.max);
                }
            });
        });
    }
}

该类封装了对 ZangoDB 集合的常用操作,包括、插入、删除、查找、最大值、数量统计、sum 聚合 、更新、更新或插入等。每个方法都提供了详细的注释说明其功能和用法。

扩展调用示例

//localDb.ts
import * as zanGoDb from "@insertish/zangodb/dist/zangodb.min.js";
import CollectionDcc from "@/core/db/CollectionDcc.ts";

let db = new zanGoDb.Db('showDataStore',{images:[],pages:[],apiData:[],dataRemotes:[]});
export const imageCollection = new CollectionDcc(db.collection("images"));
export const pagesCollection = new CollectionDcc(db.collection("pages"));
export const remoteApiDataCollection = new CollectionDcc(db.collection("apiData"));
export const remoteApisCollection = new CollectionDcc(db.collection("dataRemotes"));

数据查询调用示例

import {remoteApisCollection} from "../../../db/localDb";
const handleSubmit = () => {
	//这样我们一行代码变实现了更新或插入的调用
	remoteApisCollection.updateOrInsertById({...values}).then(() => {
		  toast.success('保存成功');
		  isEdit.value = false
		  reloadList();
		}).catch((error) => {
		  isShow.value = true
		 toast.error('保存失败' + error);
		})
}