commit 66b381bffe1fa378a22df09a0b9b8f1f3fed5f39 Author: abearxiong Date: Wed Oct 29 18:07:59 2025 +0800 test diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c9aebec --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +MONGODB_HOST=light.xiongxiao.me +MONGODB_PORT=9997 +MONGODB_DBNAME=* +MONGODB_USERNAME=root +MONGODB_PASSWORD=* \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3ed2411 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules + +.env +!.env*.example \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3bd8cb9 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# MongoDB 连接测试项目 + +这个项目包含了 MongoDB 数据库连接的配置和测试代码。 + +## 配置 + +### 1. 修改连接信息 + +编辑 `src/connect.ts` 文件中的用户名和密码: + +```typescript +const username = 'your_username'; // 替换为您的用户名 +const password = 'your_password'; // 替换为您的密码 +``` + +### 2. 安装依赖 + +```bash +pnpm install +``` + +## 运行测试 + +### 方式一:直接运行 TypeScript 文件 + +```bash +# 测试连接 +pnpm test + +# 或者 +pnpm dev +``` + +### 方式二:编译后运行 + +```bash +# 编译 TypeScript +pnpm build + +# 运行编译后的 JavaScript +node dist/connect.js +``` + +### 方式三:运行示例程序 + +```bash +# 运行包含数据库操作的示例 +tsx src/example.ts +``` + +## 项目结构 + +``` +├── src/ +│ ├── connect.ts # MongoDB 连接配置和测试函数 +│ └── example.ts # 使用示例 +├── package.json # 项目配置 +├── tsconfig.json # TypeScript 配置 +└── README.md # 说明文档 +``` + +## 功能说明 + +### `connectToDatabase()` +- 连接到 MongoDB 数据库 +- 返回数据库实例用于后续操作 + +### `testConnection()` +- 测试 MongoDB 连接是否正常 +- 列出可用的数据库 +- 返回连接状态(成功/失败) + +## 注意事项 + +1. 请确保 MongoDB 服务器正在运行 +2. 检查网络连接和防火墙设置 +3. 确认用户名、密码和数据库权限正确 +4. 如果连接失败,检查服务器地址和端口是否正确 + +## 连接字符串格式 + +``` +mongodb://username:password@host:port/?authSource=authDatabase +``` + +当前配置: +- 主机:light.xiongxiao.me +- 端口:9997 +- 认证数据库:admin \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..302c2ca --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "test_mongo", + "version": "0.0.1", + "description": "", + "main": "index.js", + "scripts": { + "build": "tsc", + "dev": "tsx src/connect.ts", + "test": "tsx src/connect.ts", + "test-connection": "node test-connection.js", + "test-mongoose": "tsx src/mongoose-example.ts", + "demo-mongoose": "tsx src/mongoose-demo.ts" + }, + "keywords": [], + "author": "abearxiong (https://www.xiongxiao.me)", + "license": "MIT", + "packageManager": "pnpm@10.19.0", + "type": "module", + "dependencies": { + "dotenv": "^17.2.3", + "mongodb": "^6.20.0", + "mongoose": "^8.19.2" + }, + "devDependencies": { + "@types/node": "^24.9.2", + "tsx": "^4.20.6", + "typescript": "^5.9.3" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..a9562e5 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,533 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + dotenv: + specifier: ^17.2.3 + version: 17.2.3 + mongodb: + specifier: ^6.20.0 + version: 6.20.0 + mongoose: + specifier: ^8.19.2 + version: 8.19.2 + devDependencies: + '@types/node': + specifier: ^24.9.2 + version: 24.9.2 + tsx: + specifier: ^4.20.6 + version: 4.20.6 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@mongodb-js/saslprep@1.3.2': + resolution: {integrity: sha512-QgA5AySqB27cGTXBFmnpifAi7HxoGUeezwo6p9dI03MuDB6Pp33zgclqVb6oVK3j6I9Vesg0+oojW2XxB59SGg==} + + '@types/node@24.9.2': + resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@11.0.5': + resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + + bson@6.10.4: + resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==} + engines: {node: '>=16.20.1'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dotenv@17.2.3: + resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + engines: {node: '>=12'} + + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + engines: {node: '>=18'} + hasBin: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + kareem@2.6.3: + resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} + engines: {node: '>=12.0.0'} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + mongodb-connection-string-url@3.0.2: + resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} + + mongodb@6.20.0: + resolution: {integrity: sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==} + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 || ^2.0.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.3.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose@8.19.2: + resolution: {integrity: sha512-ww2T4dBV+suCbOfG5YPwj9pLCfUVyj8FEA1D3Ux1HHqutpLxGyOYEPU06iPRBW4cKr3PJfOSYsIpHWPTkz5zig==} + engines: {node: '>=16.20.1'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@5.0.0: + resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} + engines: {node: '>=14.0.0'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + +snapshots: + + '@esbuild/aix-ppc64@0.25.11': + optional: true + + '@esbuild/android-arm64@0.25.11': + optional: true + + '@esbuild/android-arm@0.25.11': + optional: true + + '@esbuild/android-x64@0.25.11': + optional: true + + '@esbuild/darwin-arm64@0.25.11': + optional: true + + '@esbuild/darwin-x64@0.25.11': + optional: true + + '@esbuild/freebsd-arm64@0.25.11': + optional: true + + '@esbuild/freebsd-x64@0.25.11': + optional: true + + '@esbuild/linux-arm64@0.25.11': + optional: true + + '@esbuild/linux-arm@0.25.11': + optional: true + + '@esbuild/linux-ia32@0.25.11': + optional: true + + '@esbuild/linux-loong64@0.25.11': + optional: true + + '@esbuild/linux-mips64el@0.25.11': + optional: true + + '@esbuild/linux-ppc64@0.25.11': + optional: true + + '@esbuild/linux-riscv64@0.25.11': + optional: true + + '@esbuild/linux-s390x@0.25.11': + optional: true + + '@esbuild/linux-x64@0.25.11': + optional: true + + '@esbuild/netbsd-arm64@0.25.11': + optional: true + + '@esbuild/netbsd-x64@0.25.11': + optional: true + + '@esbuild/openbsd-arm64@0.25.11': + optional: true + + '@esbuild/openbsd-x64@0.25.11': + optional: true + + '@esbuild/openharmony-arm64@0.25.11': + optional: true + + '@esbuild/sunos-x64@0.25.11': + optional: true + + '@esbuild/win32-arm64@0.25.11': + optional: true + + '@esbuild/win32-ia32@0.25.11': + optional: true + + '@esbuild/win32-x64@0.25.11': + optional: true + + '@mongodb-js/saslprep@1.3.2': + dependencies: + sparse-bitfield: 3.0.3 + + '@types/node@24.9.2': + dependencies: + undici-types: 7.16.0 + + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@11.0.5': + dependencies: + '@types/webidl-conversions': 7.0.3 + + bson@6.10.4: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + dotenv@17.2.3: {} + + esbuild@0.25.11: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 + + fsevents@2.3.3: + optional: true + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + kareem@2.6.3: {} + + memory-pager@1.5.0: {} + + mongodb-connection-string-url@3.0.2: + dependencies: + '@types/whatwg-url': 11.0.5 + whatwg-url: 14.2.0 + + mongodb@6.20.0: + dependencies: + '@mongodb-js/saslprep': 1.3.2 + bson: 6.10.4 + mongodb-connection-string-url: 3.0.2 + + mongoose@8.19.2: + dependencies: + bson: 6.10.4 + kareem: 2.6.3 + mongodb: 6.20.0 + mpath: 0.9.0 + mquery: 5.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + mpath@0.9.0: {} + + mquery@5.0.0: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ms@2.1.3: {} + + punycode@2.3.1: {} + + resolve-pkg-maps@1.0.0: {} + + sift@17.1.3: {} + + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + tsx@4.20.6: + dependencies: + esbuild: 0.25.11 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + typescript@5.9.3: {} + + undici-types@7.16.0: {} + + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 diff --git a/src/connect.ts b/src/connect.ts new file mode 100644 index 0000000..6a9d71f --- /dev/null +++ b/src/connect.ts @@ -0,0 +1,105 @@ +import { MongoClient } from 'mongodb'; +import mongoose from 'mongoose'; +import dotenv from 'dotenv'; +dotenv.config(); +// MongoDB 连接配置 +const username = process.env.MONGODB_USERNAME; // 替换为您的用户名 +const password = process.env.MONGODB_PASSWORD; // 替换为您的密码 +const host = process.env.MONGODB_HOST; // 替换为您的主机 +const port = process.env.MONGODB_PORT; // 替换为您的端口 +const dbName = process.env.MONGODB_DBNAME; // 替换为您的数据库名 +const authSource = 'admin'; // 认证数据库,通常是 admin + +const uri = `mongodb://${username}:${password}@${host}:${port}/?authSource=${authSource}`; + +const client = new MongoClient(uri, { + dbName: dbName, + maxPoolSize: 10, // 连接池最大连接数 + serverSelectionTimeoutMS: 5000, // 服务器选择超时时间 + socketTimeoutMS: 45000, // Socket 超时时间 +} as any); // 临时解决类型问题 + +export async function connectToDatabase() { + try { + await client.connect(); + console.log('Connected to MongoDB'); + return client.db('test'); // Replace 'test' with your database name + } catch (error) { + console.error('Error connecting to MongoDB:', error); + throw error; + } +} + +// 测试连接函数 +export async function testConnection() { + try { + console.log('正在测试 MongoDB 连接...'); + await client.connect(); + + // 测试数据库连接 + const adminDb = client.db().admin(); + const result = await adminDb.ping(); + console.log('MongoDB 连接测试成功!', result); + + // 列出可用的数据库 + const dbs = await adminDb.listDatabases(); + console.log('可用的数据库:', dbs.databases.map(db => db.name)); + + return true; + } catch (error) { + console.error('MongoDB 连接测试失败:', error); + return false; + } finally { + await client.close(); + } +} + +// 主函数 - 用于直接运行测试 +export async function main() { + const success = await testConnection(); + if (success) { + console.log('✅ 数据库连接测试通过'); + process.exit(0); + } else { + console.log('❌ 数据库连接测试失败'); + process.exit(1); + } +} + +// 检查是否直接运行此文件 +if (import.meta.url === `file://${process.argv[1]}`) { + main().catch((error) => { + console.error('测试过程中发生错误:', error); + process.exit(1); + }); +} + +// Mongoose 连接函数 +export async function connectMongoose() { + try { + const mongooseUri = `mongodb://${username}:${password}@${host}:${port}/${dbName}?authSource=${authSource}`; + + await mongoose.connect(mongooseUri, { + maxPoolSize: 10, + serverSelectionTimeoutMS: 5000, + socketTimeoutMS: 45000, + } as any); + + console.log('Connected to MongoDB via Mongoose'); + return mongoose.connection; + } catch (error) { + console.error('Error connecting to MongoDB via Mongoose:', error); + throw error; + } +} + +// 断开 Mongoose 连接 +export async function disconnectMongoose() { + try { + await mongoose.disconnect(); + console.log('Disconnected from MongoDB via Mongoose'); + } catch (error) { + console.error('Error disconnecting from MongoDB via Mongoose:', error); + throw error; + } +} \ No newline at end of file diff --git a/src/example.ts b/src/example.ts new file mode 100644 index 0000000..7ba9b42 --- /dev/null +++ b/src/example.ts @@ -0,0 +1,129 @@ +import { connectToDatabase, testConnection } from './connect.js'; +import { testAModel, TestADocument } from './models/test.js'; + +// 创建示例数据 +async function createSampleData() { + console.log('=== 创建示例数据 ==='); + + const sampleData = [ + { + title: '学习TypeScript', + description: '学习TypeScript的基础语法和高级特性,掌握类型系统的使用方法。' + }, + { + title: 'MongoDB数据库设计', + description: '设计MongoDB的集合结构,了解文档数据库的特点和最佳实践。' + }, + { + title: 'Node.js后端开发', + description: '使用Node.js开发后端API,集成MongoDB数据库进行数据操作。' + }, + { + title: '前端项目优化', + description: '优化前端项目性能,包括代码分割、懒加载和缓存策略。' + }, + { + title: 'DevOps自动化部署', + description: '建立CI/CD流水线,实现项目的自动化测试和部署。' + } + ]; + + const createdDocuments: TestADocument[] = []; + + for (const data of sampleData) { + try { + const doc = await testAModel.create(data); + createdDocuments.push(doc); + console.log(`✅ 创建文档: ${doc.title}`); + } catch (error) { + console.error(`❌ 创建文档失败: ${data.title}`, error); + } + } + + return createdDocuments; +} + +// 演示所有操作 +async function demonstrateOperations() { + console.log('\n=== 演示 TestA 表操作 ==='); + + // 查询所有数据 + console.log('\n--- 查询所有数据 ---'); + const allDocs = await testAModel.findAll(); + console.log(`总共找到 ${allDocs.length} 条记录:`); + allDocs.forEach((doc, index) => { + console.log(`${index + 1}. ${doc.title}: ${doc.description}`); + }); + + if (allDocs.length > 0) { + // 根据ID查询 + console.log('\n--- 根据ID查询 ---'); + const firstDoc = await testAModel.findById(allDocs[0]._id!); + if (firstDoc) { + console.log(`找到文档: ${firstDoc.title}`); + } + + // 根据标题搜索 + console.log('\n--- 根据标题搜索 ---'); + const searchResults = await testAModel.findByTitle('TypeScript'); + console.log(`搜索 "TypeScript" 找到 ${searchResults.length} 条记录:`); + searchResults.forEach(doc => { + console.log(`- ${doc.title}`); + }); + + // 更新文档 + console.log('\n--- 更新文档 ---'); + const updated = await testAModel.updateById(allDocs[0]._id!, { + description: allDocs[0].description + ' [已更新]' + }); + if (updated) { + console.log(`✅ 更新成功: ${updated.title}`); + } + } + + // 统计记录数 + console.log('\n--- 统计信息 ---'); + const count = await testAModel.count(); + console.log(`数据库中共有 ${count} 条 TestA 记录`); +} + +// 使用示例 +async function example() { + try { + // 1. 测试连接 + console.log('=== 测试连接 ==='); + const isConnected = await testConnection(); + + if (!isConnected) { + console.log('连接失败,退出程序'); + return; + } + + // 2. 初始化 TestA 模型 + console.log('\n=== 初始化 TestA 模型 ==='); + await testAModel.initialize(); + console.log('TestA 模型初始化成功'); + + // 3. 清空现有数据(可选) + const existingCount = await testAModel.count(); + if (existingCount > 0) { + console.log(`\n发现 ${existingCount} 条现有记录,是否清空?`); + await testAModel.deleteAll(); + console.log('已清空现有数据'); + } + + // 4. 创建示例数据 + await createSampleData(); + + // 5. 演示各种操作 + await demonstrateOperations(); + + } catch (error) { + console.error('操作失败:', error); + } +} + +// 运行示例 +if (import.meta.url === `file://${process.argv[1]}`) { + example().catch(console.error); +} \ No newline at end of file diff --git a/src/models/test-mongoose.ts b/src/models/test-mongoose.ts new file mode 100644 index 0000000..f0c4fd3 --- /dev/null +++ b/src/models/test-mongoose.ts @@ -0,0 +1,216 @@ +import mongoose, { Schema, Document, Model } from 'mongoose'; + +// TestA 文档接口(继承 mongoose Document) +export interface ITestA extends Document { + _id: mongoose.Types.ObjectId; + title: string; + description: string; + createdAt: Date; + updatedAt: Date; +} + +// TestA Schema 定义 +const testASchema: Schema = new Schema( + { + title: { + type: String, + required: [true, 'Title is required'], + trim: true, + maxlength: [100, 'Title cannot be more than 100 characters'] + }, + description: { + type: String, + required: [true, 'Description is required'], + trim: true, + maxlength: [500, 'Description cannot be more than 500 characters'] + } + }, + { + timestamps: true, // 自动添加 createdAt 和 updatedAt + collection: 'test_a' // 指定集合名称 + } +); + +// 添加索引 +testASchema.index({ title: 1 }); +testASchema.index({ createdAt: -1 }); + +// 添加实例方法 +testASchema.methods.toJSON = function() { + const obj = this.toObject(); + obj.id = obj._id; + delete obj._id; + delete obj.__v; + return obj; +}; + +// 添加静态方法 +testASchema.statics.findByTitle = function(title: string) { + return this.find({ title: { $regex: title, $options: 'i' } }); +}; + +// 创建并导出模型 +export const TestAModel: Model = mongoose.model('TestA', testASchema); + +// TestA 服务类 - 封装常用操作 +export class TestAService { + + // 创建新的 TestA 记录 + static async create(data: Pick): Promise { + try { + const testA = new TestAModel(data); + return await testA.save(); + } catch (error) { + console.error('Error creating TestA:', error); + throw error; + } + } + + // 查找所有 TestA 记录 + static async findAll(limit: number = 50, skip: number = 0): Promise { + try { + return await TestAModel + .find({}) + .sort({ createdAt: -1 }) + .limit(limit) + .skip(skip) + .exec(); + } catch (error) { + console.error('Error finding all TestA:', error); + throw error; + } + } + + // 根据 ID 查找 TestA 记录 + static async findById(id: string): Promise { + try { + if (!mongoose.Types.ObjectId.isValid(id)) { + throw new Error('Invalid ObjectId'); + } + return await TestAModel.findById(id).exec(); + } catch (error) { + console.error('Error finding TestA by ID:', error); + throw error; + } + } + + // 根据标题查找 TestA 记录 + static async findByTitle(title: string): Promise { + try { + return await (TestAModel as any).findByTitle(title); + } catch (error) { + console.error('Error finding TestA by title:', error); + throw error; + } + } + + // 更新 TestA 记录 + static async updateById( + id: string, + updateData: Partial> + ): Promise { + try { + if (!mongoose.Types.ObjectId.isValid(id)) { + throw new Error('Invalid ObjectId'); + } + + return await TestAModel.findByIdAndUpdate( + id, + { $set: updateData }, + { + new: true, // 返回更新后的文档 + runValidators: true // 运行验证器 + } + ).exec(); + } catch (error) { + console.error('Error updating TestA:', error); + throw error; + } + } + + // 删除 TestA 记录 + static async deleteById(id: string): Promise { + try { + if (!mongoose.Types.ObjectId.isValid(id)) { + throw new Error('Invalid ObjectId'); + } + + const result = await TestAModel.findByIdAndDelete(id).exec(); + return !!result; + } catch (error) { + console.error('Error deleting TestA:', error); + throw error; + } + } + + // 删除所有 TestA 记录 + static async deleteAll(): Promise { + try { + const result = await TestAModel.deleteMany({}).exec(); + return result.deletedCount || 0; + } catch (error) { + console.error('Error deleting all TestA:', error); + throw error; + } + } + + // 统计 TestA 记录总数 + static async count(): Promise { + try { + return await TestAModel.countDocuments().exec(); + } catch (error) { + console.error('Error counting TestA:', error); + throw error; + } + } + + // 搜索 TestA 记录(标题或描述包含关键词) + static async search(keyword: string, limit: number = 20): Promise { + try { + const regex = new RegExp(keyword, 'i'); + return await TestAModel + .find({ + $or: [ + { title: { $regex: regex } }, + { description: { $regex: regex } } + ] + }) + .sort({ createdAt: -1 }) + .limit(limit) + .exec(); + } catch (error) { + console.error('Error searching TestA:', error); + throw error; + } + } + + // 分页查询 + static async paginate(page: number = 1, limit: number = 10) { + try { + const skip = (page - 1) * limit; + const [items, total] = await Promise.all([ + TestAModel.find({}) + .sort({ createdAt: -1 }) + .limit(limit) + .skip(skip) + .exec(), + TestAModel.countDocuments().exec() + ]); + + return { + items, + total, + page, + limit, + pages: Math.ceil(total / limit), + hasNext: page * limit < total, + hasPrev: page > 1 + }; + } catch (error) { + console.error('Error paginating TestA:', error); + throw error; + } + } +} + +export default TestAService; diff --git a/src/models/test.ts b/src/models/test.ts new file mode 100644 index 0000000..66e7a20 --- /dev/null +++ b/src/models/test.ts @@ -0,0 +1,116 @@ +import { MongoClient, Db, Collection, ObjectId } from 'mongodb'; +import { connectToDatabase } from '../connect.js'; + +// TestA 数据模型接口 +export interface TestADocument { + _id?: ObjectId; + title: string; + description: string; + createdAt?: Date; + updatedAt?: Date; +} + +// TestA 集合操作类 +export class TestAModel { + private db: Db | null = null; + private collection: Collection | null = null; + + constructor() {} + + // 初始化数据库连接 + async initialize(): Promise { + this.db = await connectToDatabase(); + this.collection = this.db.collection('test_a'); + } + + // 确保集合已初始化 + private ensureInitialized(): void { + if (!this.collection) { + throw new Error('TestA model not initialized. Call initialize() first.'); + } + } + + // 创建新的 TestA 记录 + async create(data: Omit): Promise { + this.ensureInitialized(); + + const now = new Date(); + const document: TestADocument = { + ...data, + createdAt: now, + updatedAt: now + }; + + const result = await this.collection!.insertOne(document); + return { + ...document, + _id: result.insertedId + }; + } + + // 查找所有 TestA 记录 + async findAll(): Promise { + this.ensureInitialized(); + return await this.collection!.find({}).toArray(); + } + + // 根据 ID 查找 TestA 记录 + async findById(id: string | ObjectId): Promise { + this.ensureInitialized(); + const objectId = typeof id === 'string' ? new ObjectId(id) : id; + return await this.collection!.findOne({ _id: objectId }); + } + + // 根据标题查找 TestA 记录 + async findByTitle(title: string): Promise { + this.ensureInitialized(); + return await this.collection!.find({ title: { $regex: title, $options: 'i' } }).toArray(); + } + + // 更新 TestA 记录 + async updateById( + id: string | ObjectId, + updateData: Partial> + ): Promise { + this.ensureInitialized(); + + const objectId = typeof id === 'string' ? new ObjectId(id) : id; + const updateDoc = { + ...updateData, + updatedAt: new Date() + }; + + const result = await this.collection!.findOneAndUpdate( + { _id: objectId }, + { $set: updateDoc }, + { returnDocument: 'after' } + ); + + return result || null; + } + + // 删除 TestA 记录 + async deleteById(id: string | ObjectId): Promise { + this.ensureInitialized(); + + const objectId = typeof id === 'string' ? new ObjectId(id) : id; + const result = await this.collection!.deleteOne({ _id: objectId }); + return result.deletedCount > 0; + } + + // 删除所有 TestA 记录 + async deleteAll(): Promise { + this.ensureInitialized(); + const result = await this.collection!.deleteMany({}); + return result.deletedCount; + } + + // 统计 TestA 记录总数 + async count(): Promise { + this.ensureInitialized(); + return await this.collection!.countDocuments(); + } +} + +// 导出单例实例 +export const testAModel = new TestAModel(); diff --git a/src/mongoose-demo.ts b/src/mongoose-demo.ts new file mode 100644 index 0000000..e5f01e3 --- /dev/null +++ b/src/mongoose-demo.ts @@ -0,0 +1,106 @@ +import mongoose from 'mongoose'; +import TestAService, { TestAModel, ITestA } from './models/test-mongoose.js'; + +// 简单的 Mongoose 模型使用演示(不需要实际数据库连接) +async function demonstrateModelDefinition() { + console.log('🚀 Mongoose TestA 模型定义演示\n'); + console.log('=' .repeat(50)); + + // 1. 显示模型信息 + console.log('📋 TestA 模型信息:'); + console.log(' - 模型名称:', TestAModel.modelName); + console.log(' - 集合名称:', TestAModel.collection.name); + + // 2. 显示 Schema 字段 + console.log('\n📝 Schema 字段定义:'); + const schemaFields = TestAModel.schema.paths; + Object.keys(schemaFields).forEach(field => { + if (!field.startsWith('_')) { + const fieldDef = schemaFields[field]; + console.log(` - ${field}: ${fieldDef.instance || 'Mixed'}`); + } + }); + + // 3. 创建一个文档实例(不保存到数据库) + console.log('\n🔧 创建文档实例(内存中):'); + const testDoc = new TestAModel({ + title: '测试标题', + description: '这是一个测试描述,用于演示 Mongoose 模型的基本功能。' + }); + + console.log(' 创建的文档:', testDoc.toJSON()); + + // 4. 验证文档 + console.log('\n✅ 验证文档:'); + const validationError = testDoc.validateSync(); + if (validationError) { + console.log(' 验证失败:', validationError.message); + } else { + console.log(' 验证通过!'); + } + + // 5. 测试无效数据 + console.log('\n❌ 测试无效数据:'); + const invalidDoc = new TestAModel({ + title: '', // 空标题应该失败 + description: 'A'.repeat(501) // 超长描述应该失败 + }); + + const invalidValidation = invalidDoc.validateSync(); + if (invalidValidation) { + console.log(' 预期的验证错误:'); + Object.keys(invalidValidation.errors).forEach(field => { + console.log(` - ${field}: ${invalidValidation.errors[field].message}`); + }); + } + + // 6. 展示 TestAService 的方法 + console.log('\n🛠️ TestAService 可用方法:'); + const serviceMethods = [ + 'create', 'findAll', 'findById', 'findByTitle', + 'updateById', 'deleteById', 'deleteAll', 'count', + 'search', 'paginate' + ]; + serviceMethods.forEach(method => { + console.log(` - TestAService.${method}()`); + }); + + // 7. 展示如何使用(伪代码) + console.log('\n📖 使用示例 (伪代码):'); + console.log(` + // 连接数据库 + await connectMongoose(); + + // 创建记录 + const record = await TestAService.create({ + title: '新标题', + description: '新描述' + }); + + // 查询记录 + const allRecords = await TestAService.findAll(); + const foundRecord = await TestAService.findById(record._id); + + // 更新记录 + const updated = await TestAService.updateById(record._id, { + title: '更新的标题' + }); + + // 删除记录 + const deleted = await TestAService.deleteById(record._id); + + // 断开连接 + await disconnectMongoose(); + `); + + console.log('\n✨ 模型定义演示完成!'); + console.log('\n💡 提示:'); + console.log(' 1. 确保 MongoDB 服务正在运行'); + console.log(' 2. 配置正确的 .env 文件'); + console.log(' 3. 使用 connectMongoose() 连接数据库'); + console.log(' 4. 使用 TestAService 的静态方法操作数据'); + console.log(' 5. 记得在操作完成后调用 disconnectMongoose()'); +} + +// 运行演示 +demonstrateModelDefinition().catch(console.error); \ No newline at end of file diff --git a/src/mongoose-example.ts b/src/mongoose-example.ts new file mode 100644 index 0000000..001b1a2 --- /dev/null +++ b/src/mongoose-example.ts @@ -0,0 +1,214 @@ +import { connectMongoose, disconnectMongoose } from './connect.js'; +import TestAService, { TestAModel, ITestA } from './models/test-mongoose.js'; + +// 演示 Mongoose TestA 模型的使用 +async function demonstrateTestAModel() { + try { + // 连接到 MongoDB + console.log('🔌 正在连接到 MongoDB...'); + await connectMongoose(); + console.log('✅ 已连接到 MongoDB'); + + // 1. 创建新记录 + console.log('\n📝 创建新的 TestA 记录...'); + const newRecord = await TestAService.create({ + title: 'Mongoose 测试记录', + description: '这是使用 Mongoose 创建的测试记录,包含完整的 CRUD 操作演示。' + }); + console.log('✅ 创建成功:', newRecord.toJSON()); + + // 2. 再创建几条记录用于测试 + const records = await Promise.all([ + TestAService.create({ + title: 'Node.js 学习笔记', + description: 'Node.js 后端开发的学习心得和实践经验总结。' + }), + TestAService.create({ + title: 'MongoDB 数据库教程', + description: '详细介绍 MongoDB 的安装、配置和基本使用方法。' + }), + TestAService.create({ + title: 'TypeScript 项目实战', + description: '使用 TypeScript 开发大型项目的最佳实践和注意事项。' + }) + ]); + console.log(`✅ 批量创建了 ${records.length} 条记录`); + + // 3. 查询所有记录 + console.log('\n🔍 查询所有 TestA 记录...'); + const allRecords = await TestAService.findAll(10); + console.log(`✅ 查询到 ${allRecords.length} 条记录:`); + allRecords.forEach((record: ITestA, index: number) => { + console.log(` ${index + 1}. ${record.title} (ID: ${record._id})`); + }); + + // 4. 根据 ID 查询 + console.log('\n🔍 根据 ID 查询记录...'); + const foundRecord = await TestAService.findById(newRecord._id.toString()); + if (foundRecord) { + console.log('✅ 查询成功:', foundRecord.toJSON()); + } else { + console.log('❌ 未找到记录'); + } + + // 5. 根据标题搜索 + console.log('\n🔍 根据标题搜索记录...'); + const searchResults = await TestAService.findByTitle('Mongoose'); + console.log(`✅ 搜索到 ${searchResults.length} 条包含 "Mongoose" 的记录:`); + searchResults.forEach((record: ITestA) => { + console.log(` - ${record.title}`); + }); + + // 6. 全文搜索 + console.log('\n🔍 全文搜索记录...'); + const fullTextResults = await TestAService.search('Node.js'); + console.log(`✅ 搜索到 ${fullTextResults.length} 条包含 "Node.js" 的记录:`); + fullTextResults.forEach((record: ITestA) => { + console.log(` - ${record.title}: ${record.description.substring(0, 50)}...`); + }); + + // 7. 分页查询 + console.log('\n📄 分页查询记录...'); + const paginatedResults = await TestAService.paginate(1, 2); + console.log('✅ 分页查询结果:'); + console.log(` 总记录数: ${paginatedResults.total}`); + console.log(` 当前页: ${paginatedResults.page}/${paginatedResults.pages}`); + console.log(` 当前页记录:`); + paginatedResults.items.forEach((record: ITestA, index: number) => { + console.log(` ${index + 1}. ${record.title}`); + }); + + // 8. 更新记录 + console.log('\n✏️ 更新记录...'); + const updatedRecord = await TestAService.updateById( + newRecord._id.toString(), + { + title: '更新后的 Mongoose 测试记录', + description: '这条记录已经被更新了,演示了 Mongoose 的更新功能。' + } + ); + if (updatedRecord) { + console.log('✅ 更新成功:', updatedRecord.toJSON()); + } else { + console.log('❌ 更新失败'); + } + + // 9. 统计记录数量 + console.log('\n📊 统计记录数量...'); + const totalCount = await TestAService.count(); + console.log(`✅ 总记录数: ${totalCount}`); + + // 10. 删除单条记录 + console.log('\n🗑️ 删除单条记录...'); + const deleteSuccess = await TestAService.deleteById(newRecord._id.toString()); + if (deleteSuccess) { + console.log('✅ 删除成功'); + } else { + console.log('❌ 删除失败'); + } + + // 11. 验证删除结果 + console.log('\n🔍 验证删除结果...'); + const afterDeleteCount = await TestAService.count(); + console.log(`✅ 删除后总记录数: ${afterDeleteCount}`); + + // 12. 使用原始 Mongoose 模型操作 + console.log('\n🔧 使用原始 Mongoose 模型操作...'); + const directRecord = new TestAModel({ + title: '直接使用 Model 创建', + description: '这是直接使用 TestAModel 创建的记录。' + }); + await directRecord.save(); + console.log('✅ 直接创建成功:', directRecord.toJSON()); + + // 使用 Mongoose 查询构建器 + const queryBuilderResults = await TestAModel + .find({ title: { $regex: '直接', $options: 'i' } }) + .select('title createdAt') + .sort({ createdAt: -1 }) + .limit(5) + .exec(); + + console.log('✅ 查询构建器结果:'); + queryBuilderResults.forEach((record: ITestA) => { + console.log(` - ${record.title} (${record.createdAt})`); + }); + + // 13. 清理测试数据(可选) + console.log('\n🧹 清理测试数据...'); + const deletedCount = await TestAService.deleteAll(); + console.log(`✅ 清理完成,删除了 ${deletedCount} 条记录`); + + } catch (error) { + console.error('❌ 演示过程中发生错误:', error); + } finally { + // 断开连接 + console.log('\n🔌 正在断开 MongoDB 连接...'); + await disconnectMongoose(); + console.log('✅ 已断开 MongoDB 连接'); + } +} + +// 错误处理演示 +async function demonstrateErrorHandling() { + try { + await connectMongoose(); + + console.log('\n🚨 错误处理演示:'); + + // 1. 无效的 ObjectId + try { + await TestAService.findById('invalid-id'); + } catch (error) { + console.log('✅ 捕获到无效 ObjectId 错误:', (error as Error).message); + } + + // 2. 验证错误 + try { + await TestAService.create({ + title: '', // 空标题会触发验证错误 + description: 'Valid description' + }); + } catch (error) { + console.log('✅ 捕获到验证错误:', (error as any).message); + } + + // 3. 字段长度超限 + try { + await TestAService.create({ + title: 'A'.repeat(101), // 超过 100 字符限制 + description: 'Valid description' + }); + } catch (error) { + console.log('✅ 捕获到长度限制错误:', (error as any).message); + } + + } catch (error) { + console.error('❌ 错误处理演示失败:', error); + } finally { + await disconnectMongoose(); + } +} + +// 主函数 +async function main() { + console.log('🚀 开始 Mongoose TestA 模型演示\n'); + console.log('=' .repeat(50)); + + await demonstrateTestAModel(); + + console.log('\n' + '='.repeat(50)); + await demonstrateErrorHandling(); + + console.log('\n✨ 演示完成!'); +} + +// 检查是否直接运行此文件 +if (import.meta.url === `file://${process.argv[1]}`) { + main().catch((error) => { + console.error('💥 主程序执行失败:', error); + process.exit(1); + }); +} + +export { demonstrateTestAModel, demonstrateErrorHandling }; \ No newline at end of file diff --git a/src/test-simple.ts b/src/test-simple.ts new file mode 100644 index 0000000..0b23bde --- /dev/null +++ b/src/test-simple.ts @@ -0,0 +1,41 @@ +import { testAModel } from './models/test.js'; + +// 简单的测试函数 +async function simpleTest() { + try { + console.log('🚀 开始测试 TestA 表...'); + + // 初始化模型 + await testAModel.initialize(); + console.log('✅ TestA 模型初始化成功'); + + // 创建一条测试记录 + const testDoc = await testAModel.create({ + title: '测试标题', + description: '这是一个测试描述,用于验证 TestA 表的功能。' + }); + console.log('✅ 创建测试记录成功:', testDoc.title); + + // 查询所有记录 + const allDocs = await testAModel.findAll(); + console.log(`✅ 查询成功,共找到 ${allDocs.length} 条记录`); + + // 显示记录详情 + allDocs.forEach((doc, index) => { + console.log(`${index + 1}. 标题: ${doc.title}`); + console.log(` 描述: ${doc.description}`); + console.log(` 创建时间: ${doc.createdAt}`); + console.log(''); + }); + + console.log('🎉 TestA 表测试完成!'); + + } catch (error) { + console.error('❌ 测试失败:', error); + } +} + +// 运行测试 +if (import.meta.url === `file://${process.argv[1]}`) { + simpleTest().catch(console.error); +} \ No newline at end of file diff --git a/test-connection.js b/test-connection.js new file mode 100644 index 0000000..43ef422 --- /dev/null +++ b/test-connection.js @@ -0,0 +1,15 @@ +// 简单的 JavaScript 测试脚本 +const { testConnection } = require('./dist/connect.js'); + +console.log('开始测试 MongoDB 连接...'); +testConnection() + .then((success) => { + if (success) { + console.log('✅ 数据库连接测试通过'); + } else { + console.log('❌ 数据库连接测试失败'); + } + }) + .catch((error) => { + console.error('测试过程中发生错误:', error); + }); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..04a17c1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file