{"id":14956973,"url":"https://github.com/ilovepixelart/ts-cache-mongoose","last_synced_at":"2026-05-09T19:14:30.165Z","repository":{"id":156756310,"uuid":"633138503","full_name":"ilovepixelart/ts-cache-mongoose","owner":"ilovepixelart","description":"Cache plugin for mongoose Queries and Aggregate (in-memory, redis)","archived":false,"fork":false,"pushed_at":"2026-04-12T23:23:01.000Z","size":1565,"stargazers_count":34,"open_issues_count":0,"forks_count":7,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-13T00:36:10.107Z","etag":null,"topics":["aggregate","backend","cache","db","memory","mongdodb","mongo","mongoose","nodejs","nosql","plugin","query","redis","schema","store","ts","ts-cache-mongoose","ttl","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ilovepixelart.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-04-26T21:35:53.000Z","updated_at":"2026-04-12T23:23:07.000Z","dependencies_parsed_at":"2024-01-09T10:47:31.506Z","dependency_job_id":"eeedb231-d758-424e-b724-9c64238551c7","html_url":"https://github.com/ilovepixelart/ts-cache-mongoose","commit_stats":{"total_commits":294,"total_committers":7,"mean_commits":42.0,"dds":"0.34013605442176875","last_synced_commit":"8deb6a10cac5022c094296942c034c58e7157e53"},"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"purl":"pkg:github/ilovepixelart/ts-cache-mongoose","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilovepixelart%2Fts-cache-mongoose","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilovepixelart%2Fts-cache-mongoose/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilovepixelart%2Fts-cache-mongoose/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilovepixelart%2Fts-cache-mongoose/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ilovepixelart","download_url":"https://codeload.github.com/ilovepixelart/ts-cache-mongoose/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilovepixelart%2Fts-cache-mongoose/sbom","scorecard":{"id":1245960,"data":{"date":"2026-04-12T23:23:12Z","repo":{"name":"github.com/ilovepixelart/ts-cache-mongoose","commit":"9c83b75d3b66d4028a6094f01641ab0a85c307be"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":8.2,"checks":[{"name":"Maintained","score":10,"reason":"29 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/14 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":10,"reason":"GitHub workflow tokens follow principle of least privilege","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/pr-check.yaml:26","Info: jobLevel 'contents' permission set to 'read': .github/workflows/pr-check.yaml:89","Info: jobLevel 'contents' permission set to 'read': .github/workflows/publish.yaml:134","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/publish.yaml:17","Info: topLevel 'contents' permission set to 'read': .github/workflows/pr-check.yaml:19","Info: topLevel 'contents' permission set to 'read': .github/workflows/publish.yaml:10","Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yaml:26"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":8,"reason":"dependency not pinned by hash detected -- score normalized to 8","details":["Warn: npmCommand not pinned by hash: .github/workflows/pr-check.yaml:73","Info:  12 out of  12 GitHub-owned GitHubAction dependencies pinned","Info:   2 out of   2 third-party GitHubAction dependencies pinned","Info:   3 out of   4 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"CII-Best-Practices","score":2,"reason":"badge detected: InProgress","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yaml:129"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"Fuzzing","score":10,"reason":"project is fuzzed","details":["Info: TypeScriptPropertyBasedTesting integration found: tests/ms.property.test.ts:3","Info: TypeScriptPropertyBasedTesting integration found: tests/ms.property.test.ts:3"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":4,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Warn: 'branch protection settings apply to administrators' is disabled on branch 'main'","Warn: 'stale review dismissal' is disabled on branch 'main'","Warn: branch 'main' does not require approvers","Warn: codeowners review is not required on branch 'main'","Warn: 'last push approval' is disabled on branch 'main'","Info: 'up-to-date branches' is required to merge on branch 'main'","Info: status check found to merge onto on branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: all commits (23) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"Contributors","score":0,"reason":"project has 0 contributing companies or organizations -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}},{"name":"CI-Tests","score":10,"reason":"8 out of 8 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}}]},"last_synced_at":"2026-04-13T00:36:13.794Z","repository_id":156756310,"created_at":"2026-04-13T00:36:13.794Z","updated_at":"2026-04-13T00:36:13.794Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32831746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"online","status_checked_at":"2026-05-09T02:00:06.633Z","response_time":123,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aggregate","backend","cache","db","memory","mongdodb","mongo","mongoose","nodejs","nosql","plugin","query","redis","schema","store","ts","ts-cache-mongoose","ttl","typescript"],"created_at":"2024-09-24T13:13:48.947Z","updated_at":"2026-05-09T19:14:30.153Z","avatar_url":"https://github.com/ilovepixelart.png","language":"TypeScript","funding_links":[],"categories":["⚡ Caching \u0026 Performance"],"sub_categories":[],"readme":"# ts-cache-mongoose\n\nCache query and aggregate in mongoose using in-memory or redis\n\n[![npm](https://img.shields.io/npm/v/ts-cache-mongoose)](https://www.npmjs.com/package/ts-cache-mongoose)\n[![npm](https://img.shields.io/npm/dt/ts-cache-mongoose)](https://www.npmjs.com/package/ts-cache-mongoose)\n[![GitHub](https://img.shields.io/github/license/ilovepixelart/ts-cache-mongoose)](https://github.com/ilovepixelart/ts-cache-mongoose/blob/main/LICENSE)\n\\\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ilovepixelart_ts-cache-mongoose\u0026metric=coverage)](https://sonarcloud.io/summary/new_code?id=ilovepixelart_ts-cache-mongoose)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ilovepixelart_ts-cache-mongoose\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ilovepixelart_ts-cache-mongoose)\n\\\n[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=ilovepixelart_ts-cache-mongoose\u0026metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=ilovepixelart_ts-cache-mongoose)\n[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ilovepixelart_ts-cache-mongoose\u0026metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ilovepixelart_ts-cache-mongoose)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=ilovepixelart_ts-cache-mongoose\u0026metric=security_rating)](https://sonarcloud.io/summary/new_code?id=ilovepixelart_ts-cache-mongoose)\n\\\n[![Socket Badge](https://badge.socket.dev/npm/package/ts-cache-mongoose)](https://socket.dev/npm/package/ts-cache-mongoose)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/ilovepixelart/ts-cache-mongoose/badge)](https://securityscorecards.dev/viewer/?uri=github.com/ilovepixelart/ts-cache-mongoose)\n[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12484/badge?v=1)](https://www.bestpractices.dev/en/projects/12484)\n\n## Motivation\n\nts-cache-mongoose is a plugin for mongoose\n\\\nI need a way to cache mongoose queries and aggregations to improve application performance. It should support both in-memory and Redis cache engines, work with all major Node.js frameworks, and be easy to use with a simple `.cache()` method on queries and aggregations.\n\n## Supports and tested with\n\n```json\n{\n  \"node\": \"20.x || 22.x || 24.x\",\n  \"mongoose\": \"\u003e=6.6.0 \u003c10\"\n}\n```\n\nCI tests against mongoose `6.12.2`, `7.6.4`, `8.23.0`, and `9.4.1`.\n\n## Features\n\n- In-memory caching\n- Redis caching\n- Cache expiration\n- Cache invalidation\n- Cache key generation\n- Cache key prefix\n- Query caching\n- Aggregate caching\n- Supports ESM and CommonJS\n\n## Installation\n\n`mongoose` is a peer dependency — install it alongside `ts-cache-mongoose`.\n\n```bash\nnpm install ts-cache-mongoose mongoose\npnpm add ts-cache-mongoose mongoose\nyarn add ts-cache-mongoose mongoose\nbun add ts-cache-mongoose mongoose\n```\n\n## Example\n\nWorks with any Node.js framework — Express, Fastify, Koa, Hono, etc:\n\n```typescript\nimport mongoose from 'mongoose'\nimport cache from 'ts-cache-mongoose'\n\n// In-memory\ncache.init(mongoose, {\n  defaultTTL: '60 seconds',\n  engine: 'memory',\n})\n\n// Or Redis\ncache.init(mongoose, {\n  defaultTTL: '60 seconds',\n  engine: 'redis',\n  engineOptions: {\n    host: 'localhost',\n    port: 6379,\n  },\n})\n\nmongoose.connect('mongodb://localhost:27017/my-database')\n```\n\n### Query caching\n\n```typescript\nconst users = await User.find({ role: 'user' }).cache('10 seconds').exec()\nconst book = await Book.findById(id).cache('1 hour').exec()\nconst count = await Book.countDocuments().cache('1 minute').exec()\nconst authors = await Book.distinct('author').cache('30 seconds').exec()\n```\n\n### Aggregate caching\n\n```typescript\nconst books = await Book.aggregate([\n  { $match: { genre: 'fantasy' } },\n  { $group: { _id: '$author', count: { $sum: 1 } } },\n]).cache('1 minute').exec()\n```\n\n### Bounded in-memory cache\n\nThe in-memory engine is unbounded by default. For workloads where query keys are driven by user input (search, filters, pagination), cap the cache so a caller generating unique cache keys cannot grow the map without limit. Two bounds are available and can be combined — eviction is LRU, and whichever bound is hit first triggers it:\n\n```typescript\ncache.init(mongoose, {\n  engine: 'memory',\n  defaultTTL: '60 seconds',\n  maxEntries: 10_000,          // cap by entry count\n  maxBytes: 50 * 1024 * 1024,  // cap by serialized bytes (50 MB)\n})\n```\n\n`maxBytes` measures entry size via `node:v8.serialize(value).byteLength` by default — handles circular references (mongoose `populate` parent-refs), single C++ call per `set`, works on Node / Bun / Deno. Provide your own `sizeCalculation` callback if you want an O(1) estimate instead:\n\n```typescript\ncache.init(mongoose, {\n  engine: 'memory',\n  maxBytes: 50 * 1024 * 1024,\n  sizeCalculation: (value) =\u003e {\n    if (Array.isArray(value)) return value.length * 512\n    return 512\n  },\n})\n```\n\nEviction is soft: the just-written entry is never dropped, even if its own size exceeds `maxBytes`. Everything older gets evicted until both bounds are satisfied (or only the new entry remains).\n\nBoth options are ignored for the Redis engine — use Redis's own `maxmemory` + `maxmemory-policy` instead.\n\n### Custom error handling\n\nBy default, cache engine failures (Redis disconnects, serialization errors, etc.) are logged via `console.error` and the query falls through to the database. Pass an `onError` callback to route them somewhere else — e.g. a structured logger, Sentry, or a metric counter:\n\n```typescript\ncache.init(mongoose, {\n  engine: 'redis',\n  defaultTTL: '60 seconds',\n  engineOptions: { host: 'localhost', port: 6379 },\n  onError: (error) =\u003e {\n    logger.warn({ err: error }, 'cache engine failure')\n  },\n})\n```\n\nThe callback receives the raw `Error`. Cache reads and writes never throw — a failing engine degrades to a cache miss.\n\n### Cache invalidation\n\n```typescript\nconst instance = cache.init(mongoose, { engine: 'memory', defaultTTL: '60 seconds' })\n\n// Clear all cache\nawait instance.clear()\n\n// Or use custom cache key\nconst user = await User.findById(id).cache('1 minute', 'user-key').exec()\nawait instance.clear('user-key')\n```\n\n### NestJS (because it's special)\n\nImport `CacheModule` from `ts-cache-mongoose/nest`:\n\n```typescript\nimport { CacheModule } from 'ts-cache-mongoose/nest'\n\n@Module({\n  imports: [\n    MongooseModule.forRoot(process.env.MONGO_URI),\n    CacheModule.forRoot({\n      engine: 'memory',\n      defaultTTL: '60 seconds',\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\nWith `ConfigService`:\n\n```typescript\nCacheModule.forRootAsync({\n  inject: [ConfigService],\n  useFactory: (config: ConfigService) =\u003e ({\n    engine: config.get('CACHE_ENGINE', 'memory'),\n    defaultTTL: config.get('CACHE_TTL', '60 seconds'),\n  }),\n})\n```\n\nInject `CacheService` for programmatic cache clearing:\n\n```typescript\nimport { CacheService } from 'ts-cache-mongoose/nest'\n\n@Injectable()\nexport class SomeService {\n  constructor(private readonly cacheService: CacheService) {}\n\n  async clearUserCache() {\n    await this.cacheService.clear('user-cache-key')\n  }\n}\n```\n\n## Contributing\n\nCheck [CONTRIBUTING.md](CONTRIBUTING.md)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n\n## Check my other projects\n\n- [ts-migrate-mongoose](https://github.com/ilovepixelart/ts-migrate-mongoose) - Migration framework for mongoose\n- [ts-patch-mongoose](https://github.com/ilovepixelart/ts-patch-mongoose) - Patch history \u0026 events plugin for mongoose\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filovepixelart%2Fts-cache-mongoose","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filovepixelart%2Fts-cache-mongoose","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filovepixelart%2Fts-cache-mongoose/lists"}