cfsa-antigravity 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,1169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mongodb
|
|
3
|
+
description: "Expert MongoDB development guide covering schema design (embedding vs referencing), index strategies (compound, multikey, text, TTL, partial), aggregation pipeline, transactions, change streams, Node.js driver, Mongoose ODM, Atlas features (search, vector search, triggers), sharding, read/write concerns, connection pooling, GridFS, and security (RBAC, field-level encryption)."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# MongoDB Expert
|
|
8
|
+
|
|
9
|
+
## 1. Schema Design
|
|
10
|
+
|
|
11
|
+
### Embedding vs Referencing
|
|
12
|
+
|
|
13
|
+
**Embed** when data is accessed together and the embedded document is bounded in size. **Reference** when data is large, unbounded, or accessed independently.
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
// Embedded: address belongs to the user, accessed together, bounded
|
|
17
|
+
{
|
|
18
|
+
_id: ObjectId("..."),
|
|
19
|
+
name: "Alice Johnson",
|
|
20
|
+
email: "alice@example.com",
|
|
21
|
+
address: {
|
|
22
|
+
street: "123 Main St",
|
|
23
|
+
city: "Portland",
|
|
24
|
+
state: "OR",
|
|
25
|
+
zip: "97201"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Referenced: orders are unbounded and queried independently
|
|
30
|
+
// users collection
|
|
31
|
+
{
|
|
32
|
+
_id: ObjectId("user1"),
|
|
33
|
+
name: "Alice Johnson",
|
|
34
|
+
email: "alice@example.com"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// orders collection
|
|
38
|
+
{
|
|
39
|
+
_id: ObjectId("order1"),
|
|
40
|
+
userId: ObjectId("user1"), // reference to user
|
|
41
|
+
items: [
|
|
42
|
+
{ productId: ObjectId("prod1"), name: "Widget", quantity: 2, price: 29.99 },
|
|
43
|
+
{ productId: ObjectId("prod2"), name: "Gadget", quantity: 1, price: 49.99 }
|
|
44
|
+
],
|
|
45
|
+
total: 109.97,
|
|
46
|
+
status: "shipped",
|
|
47
|
+
createdAt: ISODate("2025-02-15T10:30:00Z")
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Decision Guide
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Embed when:
|
|
55
|
+
- Data is read together in the same query (1:1 or 1:few)
|
|
56
|
+
- Child data does not grow unboundedly
|
|
57
|
+
- Child data does not need independent access
|
|
58
|
+
- You want atomic updates (single document = atomic)
|
|
59
|
+
|
|
60
|
+
Reference when:
|
|
61
|
+
- Data grows unboundedly (comments, orders, logs)
|
|
62
|
+
- Child data is large (> 100 KB per child)
|
|
63
|
+
- Child data is accessed independently
|
|
64
|
+
- Many-to-many relationships exist
|
|
65
|
+
- Data is shared across multiple parent documents
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Schema Validation
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
db.createCollection("products", {
|
|
72
|
+
validator: {
|
|
73
|
+
$jsonSchema: {
|
|
74
|
+
bsonType: "object",
|
|
75
|
+
required: ["name", "price", "category", "status"],
|
|
76
|
+
properties: {
|
|
77
|
+
name: {
|
|
78
|
+
bsonType: "string",
|
|
79
|
+
minLength: 1,
|
|
80
|
+
maxLength: 200,
|
|
81
|
+
description: "Product name is required"
|
|
82
|
+
},
|
|
83
|
+
price: {
|
|
84
|
+
bsonType: "decimal",
|
|
85
|
+
minimum: 0,
|
|
86
|
+
description: "Price must be a non-negative decimal"
|
|
87
|
+
},
|
|
88
|
+
category: {
|
|
89
|
+
bsonType: "string",
|
|
90
|
+
enum: ["electronics", "clothing", "food", "books", "home"],
|
|
91
|
+
description: "Category must be one of the allowed values"
|
|
92
|
+
},
|
|
93
|
+
status: {
|
|
94
|
+
bsonType: "string",
|
|
95
|
+
enum: ["draft", "active", "archived"],
|
|
96
|
+
description: "Status must be draft, active, or archived"
|
|
97
|
+
},
|
|
98
|
+
tags: {
|
|
99
|
+
bsonType: "array",
|
|
100
|
+
items: { bsonType: "string" },
|
|
101
|
+
maxItems: 20,
|
|
102
|
+
description: "Tags must be an array of strings"
|
|
103
|
+
},
|
|
104
|
+
specs: {
|
|
105
|
+
bsonType: "object",
|
|
106
|
+
description: "Product specifications"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
validationLevel: "strict",
|
|
112
|
+
validationAction: "error"
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Common Patterns
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
// Polymorphic pattern: different shapes in the same collection
|
|
120
|
+
// Use a discriminator field
|
|
121
|
+
{
|
|
122
|
+
_id: ObjectId("..."),
|
|
123
|
+
type: "blog_post",
|
|
124
|
+
title: "MongoDB Patterns",
|
|
125
|
+
body: "...",
|
|
126
|
+
tags: ["mongodb", "patterns"],
|
|
127
|
+
publishedAt: ISODate("2025-02-15")
|
|
128
|
+
}
|
|
129
|
+
{
|
|
130
|
+
_id: ObjectId("..."),
|
|
131
|
+
type: "video",
|
|
132
|
+
title: "MongoDB Tutorial",
|
|
133
|
+
url: "https://example.com/video.mp4",
|
|
134
|
+
duration: 3600,
|
|
135
|
+
publishedAt: ISODate("2025-02-14")
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Bucket pattern: group time-series data to reduce document count
|
|
139
|
+
{
|
|
140
|
+
sensorId: "temp-001",
|
|
141
|
+
bucket: ISODate("2025-02-15T10:00:00Z"), // 1-hour bucket
|
|
142
|
+
measurements: [
|
|
143
|
+
{ ts: ISODate("2025-02-15T10:00:12Z"), value: 22.5 },
|
|
144
|
+
{ ts: ISODate("2025-02-15T10:01:03Z"), value: 22.6 },
|
|
145
|
+
{ ts: ISODate("2025-02-15T10:02:15Z"), value: 22.4 }
|
|
146
|
+
],
|
|
147
|
+
count: 3,
|
|
148
|
+
min: 22.4,
|
|
149
|
+
max: 22.6,
|
|
150
|
+
avg: 22.5
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Computed pattern: store precomputed values for fast reads
|
|
154
|
+
{
|
|
155
|
+
_id: ObjectId("..."),
|
|
156
|
+
productId: ObjectId("prod1"),
|
|
157
|
+
totalReviews: 142,
|
|
158
|
+
averageRating: 4.3,
|
|
159
|
+
ratingDistribution: { "1": 5, "2": 8, "3": 15, "4": 52, "5": 62 },
|
|
160
|
+
lastUpdated: ISODate("2025-02-15T12:00:00Z")
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 2. Index Strategies
|
|
167
|
+
|
|
168
|
+
### Compound Indexes
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
// Compound index: supports queries that match a prefix of the index keys
|
|
172
|
+
// Order matters: equality -> sort -> range (ESR rule)
|
|
173
|
+
db.orders.createIndex({ status: 1, createdAt: -1 });
|
|
174
|
+
// Supports: { status: "shipped" }
|
|
175
|
+
// Supports: { status: "shipped" }, sorted by createdAt DESC
|
|
176
|
+
// Does NOT efficiently support: { createdAt: { $gt: date } } alone
|
|
177
|
+
|
|
178
|
+
// Covered query: index contains all fields the query needs
|
|
179
|
+
db.orders.createIndex({ userId: 1, status: 1, total: 1, createdAt: -1 });
|
|
180
|
+
// This query is fully covered (no document fetch):
|
|
181
|
+
db.orders.find(
|
|
182
|
+
{ userId: ObjectId("..."), status: "shipped" },
|
|
183
|
+
{ total: 1, createdAt: 1, _id: 0 }
|
|
184
|
+
).sort({ createdAt: -1 });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Multikey Indexes
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
// Automatically created when indexing array fields
|
|
191
|
+
db.products.createIndex({ tags: 1 });
|
|
192
|
+
// Supports: db.products.find({ tags: "electronics" })
|
|
193
|
+
// Supports: db.products.find({ tags: { $in: ["electronics", "sale"] } })
|
|
194
|
+
|
|
195
|
+
// Compound with array field (only ONE array field per compound index)
|
|
196
|
+
db.products.createIndex({ category: 1, tags: 1 });
|
|
197
|
+
// VALID: category is scalar, tags is array
|
|
198
|
+
// INVALID: db.collection.createIndex({ tags: 1, colors: 1 }) where both are arrays
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Text Indexes
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
// Full-text search index
|
|
205
|
+
db.articles.createIndex(
|
|
206
|
+
{ title: "text", body: "text", tags: "text" },
|
|
207
|
+
{ weights: { title: 10, tags: 5, body: 1 }, name: "article_search" }
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// Text search query
|
|
211
|
+
db.articles.find(
|
|
212
|
+
{ $text: { $search: "mongodb aggregation pipeline" } },
|
|
213
|
+
{ score: { $meta: "textScore" } }
|
|
214
|
+
).sort({ score: { $meta: "textScore" } }).limit(20);
|
|
215
|
+
|
|
216
|
+
// Phrase search
|
|
217
|
+
db.articles.find({ $text: { $search: "\"aggregation pipeline\"" } });
|
|
218
|
+
|
|
219
|
+
// Exclude terms
|
|
220
|
+
db.articles.find({ $text: { $search: "mongodb -mongoose" } });
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### TTL Indexes
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
// Automatically delete documents after a period
|
|
227
|
+
db.sessions.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
228
|
+
// Document is deleted when current time > expiresAt
|
|
229
|
+
|
|
230
|
+
// Fixed TTL from creation
|
|
231
|
+
db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 2592000 });
|
|
232
|
+
// Documents deleted 30 days after createdAt
|
|
233
|
+
|
|
234
|
+
// Insert with explicit expiry
|
|
235
|
+
db.sessions.insertOne({
|
|
236
|
+
sessionId: "abc123",
|
|
237
|
+
userId: ObjectId("..."),
|
|
238
|
+
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours from now
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Partial Indexes
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// Index only documents matching a filter condition
|
|
246
|
+
db.orders.createIndex(
|
|
247
|
+
{ createdAt: -1 },
|
|
248
|
+
{ partialFilterExpression: { status: "pending" } }
|
|
249
|
+
);
|
|
250
|
+
// Smaller index, faster writes, only useful for queries filtering on status: "pending"
|
|
251
|
+
|
|
252
|
+
// Sparse index: only indexes documents where the field exists
|
|
253
|
+
db.users.createIndex({ email: 1 }, { unique: true, sparse: true });
|
|
254
|
+
// Allows multiple documents without the email field
|
|
255
|
+
// But unique among those that have it
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Wildcard Indexes
|
|
259
|
+
|
|
260
|
+
```javascript
|
|
261
|
+
// Index all fields in a subdocument (for dynamic/unknown field names)
|
|
262
|
+
db.products.createIndex({ "attributes.$**": 1 });
|
|
263
|
+
// Supports: db.products.find({ "attributes.color": "red" })
|
|
264
|
+
// Supports: db.products.find({ "attributes.weight": { $lt: 5 } })
|
|
265
|
+
// Does NOT support compound queries across multiple attribute fields efficiently
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 3. Aggregation Pipeline
|
|
271
|
+
|
|
272
|
+
### Core Stages
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
// Multi-stage aggregation: filter -> group -> sort -> project
|
|
276
|
+
db.orders.aggregate([
|
|
277
|
+
// Stage 1: Match (filter early to reduce data)
|
|
278
|
+
{ $match: {
|
|
279
|
+
status: "completed",
|
|
280
|
+
createdAt: { $gte: ISODate("2025-01-01"), $lt: ISODate("2025-02-01") }
|
|
281
|
+
}},
|
|
282
|
+
|
|
283
|
+
// Stage 2: Group by user, calculate totals
|
|
284
|
+
{ $group: {
|
|
285
|
+
_id: "$userId",
|
|
286
|
+
orderCount: { $sum: 1 },
|
|
287
|
+
totalSpent: { $sum: "$total" },
|
|
288
|
+
avgOrderValue: { $avg: "$total" },
|
|
289
|
+
lastOrder: { $max: "$createdAt" }
|
|
290
|
+
}},
|
|
291
|
+
|
|
292
|
+
// Stage 3: Filter grouped results
|
|
293
|
+
{ $match: { totalSpent: { $gte: 100 } } },
|
|
294
|
+
|
|
295
|
+
// Stage 4: Sort by total spent descending
|
|
296
|
+
{ $sort: { totalSpent: -1 } },
|
|
297
|
+
|
|
298
|
+
// Stage 5: Limit to top 10
|
|
299
|
+
{ $limit: 10 },
|
|
300
|
+
|
|
301
|
+
// Stage 6: Lookup user details
|
|
302
|
+
{ $lookup: {
|
|
303
|
+
from: "users",
|
|
304
|
+
localField: "_id",
|
|
305
|
+
foreignField: "_id",
|
|
306
|
+
as: "user"
|
|
307
|
+
}},
|
|
308
|
+
{ $unwind: "$user" },
|
|
309
|
+
|
|
310
|
+
// Stage 7: Project final shape
|
|
311
|
+
{ $project: {
|
|
312
|
+
_id: 0,
|
|
313
|
+
userName: "$user.name",
|
|
314
|
+
email: "$user.email",
|
|
315
|
+
orderCount: 1,
|
|
316
|
+
totalSpent: { $round: ["$totalSpent", 2] },
|
|
317
|
+
avgOrderValue: { $round: ["$avgOrderValue", 2] },
|
|
318
|
+
lastOrder: 1
|
|
319
|
+
}}
|
|
320
|
+
]);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Lookup with Pipeline (Subquery Join)
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
db.orders.aggregate([
|
|
327
|
+
{ $lookup: {
|
|
328
|
+
from: "products",
|
|
329
|
+
let: { productIds: "$items.productId" },
|
|
330
|
+
pipeline: [
|
|
331
|
+
{ $match: { $expr: { $in: ["$_id", "$$productIds"] } } },
|
|
332
|
+
{ $project: { name: 1, price: 1, category: 1 } }
|
|
333
|
+
],
|
|
334
|
+
as: "productDetails"
|
|
335
|
+
}}
|
|
336
|
+
]);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Faceted Search
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
db.products.aggregate([
|
|
343
|
+
{ $match: { $text: { $search: "laptop" } } },
|
|
344
|
+
{ $facet: {
|
|
345
|
+
results: [
|
|
346
|
+
{ $sort: { score: { $meta: "textScore" } } },
|
|
347
|
+
{ $skip: 0 },
|
|
348
|
+
{ $limit: 20 },
|
|
349
|
+
{ $project: { name: 1, price: 1, category: 1 } }
|
|
350
|
+
],
|
|
351
|
+
categoryFacets: [
|
|
352
|
+
{ $group: { _id: "$category", count: { $sum: 1 } } },
|
|
353
|
+
{ $sort: { count: -1 } }
|
|
354
|
+
],
|
|
355
|
+
priceRanges: [
|
|
356
|
+
{ $bucket: {
|
|
357
|
+
groupBy: "$price",
|
|
358
|
+
boundaries: [0, 500, 1000, 2000, 5000],
|
|
359
|
+
default: "5000+",
|
|
360
|
+
output: { count: { $sum: 1 } }
|
|
361
|
+
}}
|
|
362
|
+
],
|
|
363
|
+
totalCount: [
|
|
364
|
+
{ $count: "total" }
|
|
365
|
+
]
|
|
366
|
+
}}
|
|
367
|
+
]);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Window Functions (MongoDB 5.0+)
|
|
371
|
+
|
|
372
|
+
```javascript
|
|
373
|
+
db.sales.aggregate([
|
|
374
|
+
{ $setWindowFields: {
|
|
375
|
+
partitionBy: "$region",
|
|
376
|
+
sortBy: { date: 1 },
|
|
377
|
+
output: {
|
|
378
|
+
runningTotal: {
|
|
379
|
+
$sum: "$amount",
|
|
380
|
+
window: { documents: ["unbounded", "current"] }
|
|
381
|
+
},
|
|
382
|
+
movingAvg7Day: {
|
|
383
|
+
$avg: "$amount",
|
|
384
|
+
window: { range: [-6, "current"], unit: "day" }
|
|
385
|
+
},
|
|
386
|
+
rank: {
|
|
387
|
+
$rank: {}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}}
|
|
391
|
+
]);
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## 4. Transactions
|
|
397
|
+
|
|
398
|
+
### Multi-Document Transactions
|
|
399
|
+
|
|
400
|
+
```javascript
|
|
401
|
+
const session = client.startSession();
|
|
402
|
+
|
|
403
|
+
try {
|
|
404
|
+
session.startTransaction({
|
|
405
|
+
readConcern: { level: "snapshot" },
|
|
406
|
+
writeConcern: { w: "majority" },
|
|
407
|
+
readPreference: "primary"
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
const ordersCol = db.collection("orders");
|
|
411
|
+
const inventoryCol = db.collection("inventory");
|
|
412
|
+
const paymentsCol = db.collection("payments");
|
|
413
|
+
|
|
414
|
+
// Create order
|
|
415
|
+
const order = {
|
|
416
|
+
userId: userId,
|
|
417
|
+
items: cartItems,
|
|
418
|
+
total: cartTotal,
|
|
419
|
+
status: "confirmed",
|
|
420
|
+
createdAt: new Date()
|
|
421
|
+
};
|
|
422
|
+
const { insertedId } = await ordersCol.insertOne(order, { session });
|
|
423
|
+
|
|
424
|
+
// Decrement inventory for each item
|
|
425
|
+
for (const item of cartItems) {
|
|
426
|
+
const result = await inventoryCol.updateOne(
|
|
427
|
+
{ productId: item.productId, quantity: { $gte: item.quantity } },
|
|
428
|
+
{ $inc: { quantity: -item.quantity } },
|
|
429
|
+
{ session }
|
|
430
|
+
);
|
|
431
|
+
if (result.modifiedCount === 0) {
|
|
432
|
+
throw new Error(`Insufficient inventory for product ${item.productId}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Record payment
|
|
437
|
+
await paymentsCol.insertOne({
|
|
438
|
+
orderId: insertedId,
|
|
439
|
+
amount: cartTotal,
|
|
440
|
+
method: paymentMethod,
|
|
441
|
+
status: "captured",
|
|
442
|
+
createdAt: new Date()
|
|
443
|
+
}, { session });
|
|
444
|
+
|
|
445
|
+
await session.commitTransaction();
|
|
446
|
+
return { orderId: insertedId };
|
|
447
|
+
|
|
448
|
+
} catch (error) {
|
|
449
|
+
await session.abortTransaction();
|
|
450
|
+
throw error;
|
|
451
|
+
} finally {
|
|
452
|
+
session.endSession();
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Transaction Best Practices
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
- Keep transactions short (< 60 seconds, default timeout)
|
|
460
|
+
- Minimize the number of documents touched
|
|
461
|
+
- Use retryable writes (enabled by default in driver 4.0+)
|
|
462
|
+
- Read and write to the primary in transactions
|
|
463
|
+
- Transactions work across collections and databases in replica sets
|
|
464
|
+
- Transactions work across shards in sharded clusters (MongoDB 4.2+)
|
|
465
|
+
- Avoid transactions when a single-document update suffices (single-doc ops are already atomic)
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## 5. Change Streams
|
|
471
|
+
|
|
472
|
+
```javascript
|
|
473
|
+
// Watch for changes on a collection
|
|
474
|
+
const changeStream = db.collection("orders").watch(
|
|
475
|
+
[{ $match: { "fullDocument.status": "confirmed" } }],
|
|
476
|
+
{ fullDocument: "updateLookup" }
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
changeStream.on("change", async (change) => {
|
|
480
|
+
switch (change.operationType) {
|
|
481
|
+
case "insert":
|
|
482
|
+
console.log("New order:", change.fullDocument);
|
|
483
|
+
await sendOrderConfirmation(change.fullDocument);
|
|
484
|
+
break;
|
|
485
|
+
case "update":
|
|
486
|
+
console.log("Order updated:", change.documentKey._id);
|
|
487
|
+
console.log("Changed fields:", change.updateDescription.updatedFields);
|
|
488
|
+
break;
|
|
489
|
+
case "delete":
|
|
490
|
+
console.log("Order deleted:", change.documentKey._id);
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
// Resume from a specific point (survives app restarts)
|
|
496
|
+
const resumeToken = change._id;
|
|
497
|
+
const resumedStream = db.collection("orders").watch([], {
|
|
498
|
+
resumeAfter: resumeToken
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// Watch all collections in a database
|
|
502
|
+
const dbStream = db.watch();
|
|
503
|
+
|
|
504
|
+
// Watch the entire deployment
|
|
505
|
+
const clusterStream = client.watch();
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## 6. Node.js Driver
|
|
511
|
+
|
|
512
|
+
### Connection and Configuration
|
|
513
|
+
|
|
514
|
+
```typescript
|
|
515
|
+
import { MongoClient, ServerApiVersion } from "mongodb";
|
|
516
|
+
|
|
517
|
+
const client = new MongoClient(process.env.MONGODB_URI, {
|
|
518
|
+
serverApi: { version: ServerApiVersion.v1, strict: true },
|
|
519
|
+
maxPoolSize: 50, // Max connections in pool
|
|
520
|
+
minPoolSize: 5, // Min connections kept open
|
|
521
|
+
maxIdleTimeMS: 30000, // Close idle connections after 30s
|
|
522
|
+
connectTimeoutMS: 10000, // Connection timeout
|
|
523
|
+
socketTimeoutMS: 45000, // Socket timeout
|
|
524
|
+
retryWrites: true, // Retry failed writes
|
|
525
|
+
retryReads: true, // Retry failed reads
|
|
526
|
+
w: "majority", // Default write concern
|
|
527
|
+
readPreference: "secondaryPreferred", // Read from secondaries when possible
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// Connection lifecycle
|
|
531
|
+
async function connectDB(): Promise<void> {
|
|
532
|
+
await client.connect();
|
|
533
|
+
await client.db("admin").command({ ping: 1 });
|
|
534
|
+
console.log("Connected to MongoDB");
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Graceful shutdown
|
|
538
|
+
process.on("SIGINT", async () => {
|
|
539
|
+
await client.close();
|
|
540
|
+
process.exit(0);
|
|
541
|
+
});
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### CRUD Operations
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
const db = client.db("myapp");
|
|
548
|
+
const users = db.collection("users");
|
|
549
|
+
|
|
550
|
+
// Insert
|
|
551
|
+
const result = await users.insertOne({
|
|
552
|
+
name: "Alice",
|
|
553
|
+
email: "alice@example.com",
|
|
554
|
+
createdAt: new Date(),
|
|
555
|
+
});
|
|
556
|
+
console.log("Inserted ID:", result.insertedId);
|
|
557
|
+
|
|
558
|
+
// Bulk insert
|
|
559
|
+
const bulkResult = await users.insertMany([
|
|
560
|
+
{ name: "Bob", email: "bob@example.com" },
|
|
561
|
+
{ name: "Carol", email: "carol@example.com" },
|
|
562
|
+
], { ordered: false }); // ordered: false continues on error
|
|
563
|
+
|
|
564
|
+
// Find with projection and sort
|
|
565
|
+
const activeUsers = await users
|
|
566
|
+
.find({ active: true })
|
|
567
|
+
.project({ name: 1, email: 1, _id: 0 })
|
|
568
|
+
.sort({ createdAt: -1 })
|
|
569
|
+
.limit(20)
|
|
570
|
+
.toArray();
|
|
571
|
+
|
|
572
|
+
// Update
|
|
573
|
+
await users.updateOne(
|
|
574
|
+
{ _id: userId },
|
|
575
|
+
{
|
|
576
|
+
$set: { name: "Alice Smith", updatedAt: new Date() },
|
|
577
|
+
$inc: { loginCount: 1 },
|
|
578
|
+
$push: { tags: "premium" },
|
|
579
|
+
}
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
// Update with array filters
|
|
583
|
+
await users.updateOne(
|
|
584
|
+
{ _id: userId },
|
|
585
|
+
{ $set: { "addresses.$[addr].verified": true } },
|
|
586
|
+
{ arrayFilters: [{ "addr.type": "home" }] }
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
// Delete
|
|
590
|
+
await users.deleteOne({ _id: userId });
|
|
591
|
+
await users.deleteMany({ active: false, lastLogin: { $lt: oneYearAgo } });
|
|
592
|
+
|
|
593
|
+
// Find one and update (atomic, returns the document)
|
|
594
|
+
const updated = await users.findOneAndUpdate(
|
|
595
|
+
{ _id: userId },
|
|
596
|
+
{ $set: { status: "active" } },
|
|
597
|
+
{ returnDocument: "after" } // Return the updated document
|
|
598
|
+
);
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## 7. Mongoose ODM
|
|
604
|
+
|
|
605
|
+
### Schema Definition
|
|
606
|
+
|
|
607
|
+
```typescript
|
|
608
|
+
import mongoose, { Schema, Document, Model } from "mongoose";
|
|
609
|
+
|
|
610
|
+
interface IProduct extends Document {
|
|
611
|
+
name: string;
|
|
612
|
+
slug: string;
|
|
613
|
+
price: number;
|
|
614
|
+
category: string;
|
|
615
|
+
tags: string[];
|
|
616
|
+
specs: Map<string, string>;
|
|
617
|
+
status: "draft" | "active" | "archived";
|
|
618
|
+
createdAt: Date;
|
|
619
|
+
updatedAt: Date;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const productSchema = new Schema<IProduct>({
|
|
623
|
+
name: {
|
|
624
|
+
type: String,
|
|
625
|
+
required: [true, "Product name is required"],
|
|
626
|
+
trim: true,
|
|
627
|
+
minlength: [1, "Name must be at least 1 character"],
|
|
628
|
+
maxlength: [200, "Name cannot exceed 200 characters"],
|
|
629
|
+
},
|
|
630
|
+
slug: {
|
|
631
|
+
type: String,
|
|
632
|
+
unique: true,
|
|
633
|
+
lowercase: true,
|
|
634
|
+
index: true,
|
|
635
|
+
},
|
|
636
|
+
price: {
|
|
637
|
+
type: Number,
|
|
638
|
+
required: true,
|
|
639
|
+
min: [0, "Price cannot be negative"],
|
|
640
|
+
},
|
|
641
|
+
category: {
|
|
642
|
+
type: String,
|
|
643
|
+
required: true,
|
|
644
|
+
enum: {
|
|
645
|
+
values: ["electronics", "clothing", "food", "books", "home"],
|
|
646
|
+
message: "{VALUE} is not a valid category",
|
|
647
|
+
},
|
|
648
|
+
index: true,
|
|
649
|
+
},
|
|
650
|
+
tags: {
|
|
651
|
+
type: [String],
|
|
652
|
+
validate: {
|
|
653
|
+
validator: (v: string[]) => v.length <= 20,
|
|
654
|
+
message: "A product can have at most 20 tags",
|
|
655
|
+
},
|
|
656
|
+
index: true,
|
|
657
|
+
},
|
|
658
|
+
specs: {
|
|
659
|
+
type: Map,
|
|
660
|
+
of: String,
|
|
661
|
+
},
|
|
662
|
+
status: {
|
|
663
|
+
type: String,
|
|
664
|
+
enum: ["draft", "active", "archived"],
|
|
665
|
+
default: "draft",
|
|
666
|
+
index: true,
|
|
667
|
+
},
|
|
668
|
+
}, {
|
|
669
|
+
timestamps: true, // Adds createdAt and updatedAt automatically
|
|
670
|
+
versionKey: "__v",
|
|
671
|
+
});
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### Virtuals
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
// Virtual field: computed from existing fields, not stored in DB
|
|
678
|
+
productSchema.virtual("displayPrice").get(function () {
|
|
679
|
+
return `$${this.price.toFixed(2)}`;
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
productSchema.virtual("isActive").get(function () {
|
|
683
|
+
return this.status === "active";
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// Virtual populate: reference without storing IDs
|
|
687
|
+
productSchema.virtual("reviews", {
|
|
688
|
+
ref: "Review",
|
|
689
|
+
localField: "_id",
|
|
690
|
+
foreignField: "productId",
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
// Ensure virtuals are included in JSON output
|
|
694
|
+
productSchema.set("toJSON", { virtuals: true });
|
|
695
|
+
productSchema.set("toObject", { virtuals: true });
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Middleware (Hooks)
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
// Pre-save: generate slug before saving
|
|
702
|
+
productSchema.pre("save", function (next) {
|
|
703
|
+
if (this.isModified("name")) {
|
|
704
|
+
this.slug = this.name
|
|
705
|
+
.toLowerCase()
|
|
706
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
707
|
+
.replace(/(^-|-$)/g, "");
|
|
708
|
+
}
|
|
709
|
+
next();
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
// Pre-find: always exclude archived products by default
|
|
713
|
+
productSchema.pre("find", function () {
|
|
714
|
+
if (!this.getFilter().status) {
|
|
715
|
+
this.where({ status: { $ne: "archived" } });
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
// Post-save: clear cache
|
|
720
|
+
productSchema.post("save", async function (doc) {
|
|
721
|
+
await cache.del(`product:${doc._id}`);
|
|
722
|
+
await cache.del("products:list");
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
// Pre-remove: cascade delete reviews
|
|
726
|
+
productSchema.pre("deleteOne", { document: true, query: false }, async function () {
|
|
727
|
+
await mongoose.model("Review").deleteMany({ productId: this._id });
|
|
728
|
+
});
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Population
|
|
732
|
+
|
|
733
|
+
```typescript
|
|
734
|
+
// Define reference fields
|
|
735
|
+
const orderSchema = new Schema({
|
|
736
|
+
userId: { type: Schema.Types.ObjectId, ref: "User", required: true },
|
|
737
|
+
items: [{
|
|
738
|
+
productId: { type: Schema.Types.ObjectId, ref: "Product", required: true },
|
|
739
|
+
quantity: { type: Number, required: true, min: 1 },
|
|
740
|
+
price: { type: Number, required: true },
|
|
741
|
+
}],
|
|
742
|
+
total: { type: Number, required: true },
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
// Populate references
|
|
746
|
+
const order = await Order
|
|
747
|
+
.findById(orderId)
|
|
748
|
+
.populate("userId", "name email") // Select specific fields
|
|
749
|
+
.populate("items.productId", "name price category") // Nested populate
|
|
750
|
+
.lean(); // Return plain object (faster)
|
|
751
|
+
|
|
752
|
+
// Deep populate
|
|
753
|
+
const order = await Order
|
|
754
|
+
.findById(orderId)
|
|
755
|
+
.populate({
|
|
756
|
+
path: "userId",
|
|
757
|
+
select: "name email",
|
|
758
|
+
populate: { path: "address", select: "city state" },
|
|
759
|
+
});
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
## 8. Atlas Features
|
|
765
|
+
|
|
766
|
+
### Atlas Search
|
|
767
|
+
|
|
768
|
+
```javascript
|
|
769
|
+
// Create a search index (in Atlas UI or via API)
|
|
770
|
+
// Index definition:
|
|
771
|
+
{
|
|
772
|
+
"mappings": {
|
|
773
|
+
"dynamic": false,
|
|
774
|
+
"fields": {
|
|
775
|
+
"title": { "type": "string", "analyzer": "lucene.standard" },
|
|
776
|
+
"body": { "type": "string", "analyzer": "lucene.english" },
|
|
777
|
+
"category": { "type": "stringFacet" },
|
|
778
|
+
"price": { "type": "number" },
|
|
779
|
+
"createdAt": { "type": "date" }
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// Search query using $search stage
|
|
785
|
+
db.articles.aggregate([
|
|
786
|
+
{ $search: {
|
|
787
|
+
index: "article_search",
|
|
788
|
+
compound: {
|
|
789
|
+
must: [
|
|
790
|
+
{ text: { query: "mongodb performance", path: ["title", "body"], fuzzy: { maxEdits: 1 } } }
|
|
791
|
+
],
|
|
792
|
+
filter: [
|
|
793
|
+
{ range: { path: "createdAt", gte: ISODate("2025-01-01") } }
|
|
794
|
+
]
|
|
795
|
+
},
|
|
796
|
+
highlight: { path: ["title", "body"] }
|
|
797
|
+
}},
|
|
798
|
+
{ $project: {
|
|
799
|
+
title: 1,
|
|
800
|
+
score: { $meta: "searchScore" },
|
|
801
|
+
highlights: { $meta: "searchHighlights" }
|
|
802
|
+
}},
|
|
803
|
+
{ $limit: 20 }
|
|
804
|
+
]);
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
### Atlas Vector Search
|
|
808
|
+
|
|
809
|
+
```javascript
|
|
810
|
+
// Create a vector search index
|
|
811
|
+
{
|
|
812
|
+
"fields": [
|
|
813
|
+
{
|
|
814
|
+
"type": "vector",
|
|
815
|
+
"path": "embedding",
|
|
816
|
+
"numDimensions": 1536,
|
|
817
|
+
"similarity": "cosine"
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
"type": "filter",
|
|
821
|
+
"path": "category"
|
|
822
|
+
}
|
|
823
|
+
]
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Vector search query (semantic similarity)
|
|
827
|
+
db.documents.aggregate([
|
|
828
|
+
{ $vectorSearch: {
|
|
829
|
+
index: "vector_index",
|
|
830
|
+
path: "embedding",
|
|
831
|
+
queryVector: queryEmbedding, // 1536-dimensional float array
|
|
832
|
+
numCandidates: 100,
|
|
833
|
+
limit: 10,
|
|
834
|
+
filter: { category: "technical" }
|
|
835
|
+
}},
|
|
836
|
+
{ $project: {
|
|
837
|
+
title: 1,
|
|
838
|
+
content: 1,
|
|
839
|
+
score: { $meta: "vectorSearchScore" }
|
|
840
|
+
}}
|
|
841
|
+
]);
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
### Atlas Triggers
|
|
845
|
+
|
|
846
|
+
```javascript
|
|
847
|
+
// Database trigger (responds to collection changes)
|
|
848
|
+
// Configured in Atlas UI or via App Services API
|
|
849
|
+
exports = async function(changeEvent) {
|
|
850
|
+
const { operationType, fullDocument, documentKey } = changeEvent;
|
|
851
|
+
|
|
852
|
+
if (operationType === "insert") {
|
|
853
|
+
// Send welcome email when a new user is created
|
|
854
|
+
const email = fullDocument.email;
|
|
855
|
+
const name = fullDocument.name;
|
|
856
|
+
await context.services
|
|
857
|
+
.get("email-service")
|
|
858
|
+
.send({ to: email, subject: `Welcome, ${name}!` });
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
if (operationType === "update") {
|
|
862
|
+
// Log changes for audit trail
|
|
863
|
+
const audit = context.services.get("mongodb-atlas").db("myapp").collection("audit_log");
|
|
864
|
+
await audit.insertOne({
|
|
865
|
+
collectionName: "users",
|
|
866
|
+
documentId: documentKey._id,
|
|
867
|
+
operation: operationType,
|
|
868
|
+
changes: changeEvent.updateDescription,
|
|
869
|
+
timestamp: new Date()
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
## 9. Sharding
|
|
878
|
+
|
|
879
|
+
### Shard Key Selection
|
|
880
|
+
|
|
881
|
+
```javascript
|
|
882
|
+
// Range-based sharding (good for range queries, risk of hotspots)
|
|
883
|
+
sh.shardCollection("myapp.orders", { createdAt: 1 });
|
|
884
|
+
|
|
885
|
+
// Hashed sharding (even distribution, no range queries on shard key)
|
|
886
|
+
sh.shardCollection("myapp.events", { _id: "hashed" });
|
|
887
|
+
|
|
888
|
+
// Compound shard key (balance distribution and query routing)
|
|
889
|
+
sh.shardCollection("myapp.orders", { userId: 1, createdAt: 1 });
|
|
890
|
+
// Queries filtering on userId are routed to a specific shard
|
|
891
|
+
// Queries on userId + createdAt range are efficient
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
### Shard Key Rules
|
|
895
|
+
|
|
896
|
+
```
|
|
897
|
+
- Shard key is immutable after creation (cannot change it)
|
|
898
|
+
- High cardinality: many distinct values (avoid boolean, status fields)
|
|
899
|
+
- Low frequency: no single value dominates (avoid "country" if 90% is "US")
|
|
900
|
+
- Non-monotonic: avoid auto-incrementing fields alone (causes hotspot on last shard)
|
|
901
|
+
- Query isolation: queries should include the shard key to avoid scatter-gather
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
---
|
|
905
|
+
|
|
906
|
+
## 10. Read/Write Concerns
|
|
907
|
+
|
|
908
|
+
```javascript
|
|
909
|
+
// Write concern: how many replicas must acknowledge a write
|
|
910
|
+
// w: 1 -- Primary only (fast, risk of rollback)
|
|
911
|
+
// w: majority -- Majority of replicas (safe, default for transactions)
|
|
912
|
+
// w: 0 -- Fire and forget (fastest, no acknowledgment)
|
|
913
|
+
|
|
914
|
+
await collection.insertOne(doc, { writeConcern: { w: "majority", wtimeout: 5000 } });
|
|
915
|
+
|
|
916
|
+
// Read concern: what data a query returns
|
|
917
|
+
// local -- Returns most recent data on the node (may be rolled back)
|
|
918
|
+
// majority -- Returns data committed to majority (durable)
|
|
919
|
+
// snapshot -- Point-in-time snapshot (used in transactions)
|
|
920
|
+
// linearizable -- Most strict, waits for all prior writes to be majority-committed
|
|
921
|
+
|
|
922
|
+
await collection.find({}).readConcern("majority").toArray();
|
|
923
|
+
|
|
924
|
+
// Read preference: which node handles reads
|
|
925
|
+
// primary -- All reads go to primary (default)
|
|
926
|
+
// primaryPreferred -- Primary if available, else secondary
|
|
927
|
+
// secondary -- Only secondaries
|
|
928
|
+
// secondaryPreferred -- Secondaries if available, else primary
|
|
929
|
+
// nearest -- Lowest latency node
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
---
|
|
933
|
+
|
|
934
|
+
## 11. Connection Pooling
|
|
935
|
+
|
|
936
|
+
```typescript
|
|
937
|
+
// Driver-level connection pooling
|
|
938
|
+
const client = new MongoClient(uri, {
|
|
939
|
+
maxPoolSize: 100, // Max simultaneous connections
|
|
940
|
+
minPoolSize: 10, // Keep at least 10 connections open
|
|
941
|
+
maxIdleTimeMS: 30000, // Close connections idle for 30 seconds
|
|
942
|
+
waitQueueTimeoutMS: 10000, // Fail if no connection available in 10s
|
|
943
|
+
compressors: ["zstd", "snappy"], // Network compression
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
// Connection pool monitoring
|
|
947
|
+
client.on("connectionPoolCreated", (event) => {
|
|
948
|
+
console.log("Pool created:", event.address);
|
|
949
|
+
});
|
|
950
|
+
client.on("connectionCheckedOut", (event) => {
|
|
951
|
+
console.log("Connection checked out:", event.connectionId);
|
|
952
|
+
});
|
|
953
|
+
client.on("connectionPoolCleared", (event) => {
|
|
954
|
+
console.log("Pool cleared:", event.address);
|
|
955
|
+
});
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
---
|
|
959
|
+
|
|
960
|
+
## 12. GridFS
|
|
961
|
+
|
|
962
|
+
```typescript
|
|
963
|
+
import { GridFSBucket, ObjectId } from "mongodb";
|
|
964
|
+
import { createReadStream, createWriteStream } from "fs";
|
|
965
|
+
|
|
966
|
+
const bucket = new GridFSBucket(db, { bucketName: "uploads" });
|
|
967
|
+
|
|
968
|
+
// Upload a file
|
|
969
|
+
async function uploadFile(filePath: string, filename: string, metadata: Record<string, unknown>): Promise<ObjectId> {
|
|
970
|
+
return new Promise((resolve, reject) => {
|
|
971
|
+
const uploadStream = bucket.openUploadStream(filename, {
|
|
972
|
+
metadata,
|
|
973
|
+
chunkSizeBytes: 1024 * 255, // 255 KB chunks (default)
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
createReadStream(filePath)
|
|
977
|
+
.pipe(uploadStream)
|
|
978
|
+
.on("error", reject)
|
|
979
|
+
.on("finish", () => resolve(uploadStream.id as ObjectId));
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// Download a file
|
|
984
|
+
async function downloadFile(fileId: ObjectId, destPath: string): Promise<void> {
|
|
985
|
+
return new Promise((resolve, reject) => {
|
|
986
|
+
bucket.openDownloadStream(fileId)
|
|
987
|
+
.pipe(createWriteStream(destPath))
|
|
988
|
+
.on("error", reject)
|
|
989
|
+
.on("finish", resolve);
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
// Delete a file
|
|
994
|
+
await bucket.delete(fileId);
|
|
995
|
+
|
|
996
|
+
// List files
|
|
997
|
+
const files = await bucket.find({ "metadata.userId": userId }).toArray();
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
## 13. Security
|
|
1003
|
+
|
|
1004
|
+
### RBAC (Role-Based Access Control)
|
|
1005
|
+
|
|
1006
|
+
```javascript
|
|
1007
|
+
// Create an application-specific role
|
|
1008
|
+
db.createRole({
|
|
1009
|
+
role: "appReadWrite",
|
|
1010
|
+
privileges: [
|
|
1011
|
+
{
|
|
1012
|
+
resource: { db: "myapp", collection: "orders" },
|
|
1013
|
+
actions: ["find", "insert", "update"]
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
resource: { db: "myapp", collection: "products" },
|
|
1017
|
+
actions: ["find"]
|
|
1018
|
+
}
|
|
1019
|
+
],
|
|
1020
|
+
roles: []
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// Create a user with the custom role
|
|
1024
|
+
db.createUser({
|
|
1025
|
+
user: "app_service",
|
|
1026
|
+
pwd: "secure_password_here",
|
|
1027
|
+
roles: [{ role: "appReadWrite", db: "myapp" }]
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
// Read-only analytics user
|
|
1031
|
+
db.createUser({
|
|
1032
|
+
user: "analytics",
|
|
1033
|
+
pwd: "readonly_password",
|
|
1034
|
+
roles: [{ role: "read", db: "myapp" }]
|
|
1035
|
+
});
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
### Client-Side Field Level Encryption (CSFLE)
|
|
1039
|
+
|
|
1040
|
+
```typescript
|
|
1041
|
+
import { MongoClient, ClientEncryption } from "mongodb";
|
|
1042
|
+
|
|
1043
|
+
// Configure auto-encryption
|
|
1044
|
+
const client = new MongoClient(uri, {
|
|
1045
|
+
autoEncryption: {
|
|
1046
|
+
keyVaultNamespace: "encryption.__keyVault",
|
|
1047
|
+
kmsProviders: {
|
|
1048
|
+
aws: {
|
|
1049
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
1050
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
1051
|
+
},
|
|
1052
|
+
},
|
|
1053
|
+
schemaMap: {
|
|
1054
|
+
"myapp.users": {
|
|
1055
|
+
bsonType: "object",
|
|
1056
|
+
encryptMetadata: { keyId: [dataKeyId] },
|
|
1057
|
+
properties: {
|
|
1058
|
+
ssn: {
|
|
1059
|
+
encrypt: {
|
|
1060
|
+
bsonType: "string",
|
|
1061
|
+
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
|
|
1062
|
+
// Deterministic: supports equality queries on encrypted field
|
|
1063
|
+
}
|
|
1064
|
+
},
|
|
1065
|
+
medicalRecords: {
|
|
1066
|
+
encrypt: {
|
|
1067
|
+
bsonType: "array",
|
|
1068
|
+
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
|
|
1069
|
+
// Random: more secure, no queryability
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
// Encrypted writes and reads are transparent to application code
|
|
1079
|
+
await users.insertOne({ name: "Alice", ssn: "123-45-6789", medicalRecords: [...] });
|
|
1080
|
+
const user = await users.findOne({ ssn: "123-45-6789" }); // Works with deterministic encryption
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
---
|
|
1084
|
+
|
|
1085
|
+
## 14. Common Anti-Patterns
|
|
1086
|
+
|
|
1087
|
+
### Unbounded Arrays
|
|
1088
|
+
|
|
1089
|
+
```javascript
|
|
1090
|
+
// BAD: Array grows without limit (document will exceed 16 MB)
|
|
1091
|
+
{
|
|
1092
|
+
_id: ObjectId("..."),
|
|
1093
|
+
postId: ObjectId("..."),
|
|
1094
|
+
comments: [
|
|
1095
|
+
// This array could grow to millions of entries
|
|
1096
|
+
{ userId: ObjectId("..."), text: "...", createdAt: new Date() },
|
|
1097
|
+
// ...
|
|
1098
|
+
]
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
// GOOD: Separate collection with reference
|
|
1102
|
+
// comments collection
|
|
1103
|
+
{
|
|
1104
|
+
_id: ObjectId("..."),
|
|
1105
|
+
postId: ObjectId("..."),
|
|
1106
|
+
userId: ObjectId("..."),
|
|
1107
|
+
text: "Great post!",
|
|
1108
|
+
createdAt: new Date()
|
|
1109
|
+
}
|
|
1110
|
+
// Index: { postId: 1, createdAt: -1 }
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
### Missing Indexes on Query Patterns
|
|
1114
|
+
|
|
1115
|
+
```javascript
|
|
1116
|
+
// BAD: Querying without an index (full collection scan)
|
|
1117
|
+
db.orders.find({ userId: ObjectId("..."), status: "pending" }).sort({ createdAt: -1 });
|
|
1118
|
+
|
|
1119
|
+
// GOOD: Create a compound index matching the query pattern
|
|
1120
|
+
db.orders.createIndex({ userId: 1, status: 1, createdAt: -1 });
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
### Using $where or JavaScript Expressions
|
|
1124
|
+
|
|
1125
|
+
```javascript
|
|
1126
|
+
// BAD: JavaScript execution in queries (slow, no index usage, security risk)
|
|
1127
|
+
db.users.find({ $where: "this.firstName + ' ' + this.lastName === 'John Doe'" });
|
|
1128
|
+
|
|
1129
|
+
// GOOD: Use native query operators
|
|
1130
|
+
db.users.find({ firstName: "John", lastName: "Doe" });
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
### Not Using .lean() in Mongoose
|
|
1134
|
+
|
|
1135
|
+
```typescript
|
|
1136
|
+
// BAD: Full Mongoose document with change tracking overhead
|
|
1137
|
+
const users = await User.find({ active: true });
|
|
1138
|
+
|
|
1139
|
+
// GOOD: Plain JavaScript object when you do not need Mongoose features
|
|
1140
|
+
const users = await User.find({ active: true }).lean();
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
---
|
|
1144
|
+
|
|
1145
|
+
## 15. Critical Reminders
|
|
1146
|
+
|
|
1147
|
+
### ALWAYS
|
|
1148
|
+
|
|
1149
|
+
- Create indexes for every query pattern your application uses
|
|
1150
|
+
- Use projection to return only the fields you need
|
|
1151
|
+
- Set `maxTimeMS` on queries to prevent runaway operations
|
|
1152
|
+
- Use `$match` early in aggregation pipelines to reduce data volume
|
|
1153
|
+
- Monitor slow queries with the profiler: `db.setProfilingLevel(1, { slowms: 100 })`
|
|
1154
|
+
- Use `bulkWrite` for batch operations (much faster than individual writes)
|
|
1155
|
+
- Handle `MongoServerError` code 11000 for duplicate key violations
|
|
1156
|
+
- Use `lean()` in Mongoose when you do not need document methods or change tracking
|
|
1157
|
+
- Set `retryWrites: true` and `retryReads: true` in connection options
|
|
1158
|
+
- Validate schema with `$jsonSchema` validator or Mongoose validation
|
|
1159
|
+
|
|
1160
|
+
### NEVER
|
|
1161
|
+
|
|
1162
|
+
- Store unbounded arrays in a single document (16 MB document limit)
|
|
1163
|
+
- Use `$where` or server-side JavaScript execution
|
|
1164
|
+
- Create an index on every field (each index costs write performance and storage)
|
|
1165
|
+
- Use `find()` without `limit()` on large collections
|
|
1166
|
+
- Store large binary files directly in documents (use GridFS for files > 256 KB)
|
|
1167
|
+
- Ignore write concern in production (use `w: "majority"` for important data)
|
|
1168
|
+
- Use auto-incrementing integers as `_id` in sharded clusters (causes hotspots)
|
|
1169
|
+
- Skip connection pooling configuration (defaults may not suit your workload)
|