mongodb-models-visualizer 0.1.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/README.md +212 -0
- package/dist/index.cjs +85 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +48 -0
- package/package.json +45 -0
- package/src/core/index.ts +0 -0
- package/src/core/parseSchema.ts +17 -0
- package/src/core/scanModels.ts +12 -0
- package/src/express/index.ts +1 -0
- package/src/express/middleware.ts +21 -0
- package/src/index.ts +1 -0
- package/src/ui/serverUI.ts +0 -0
- package/tsconfig.json +45 -0
- package/tsup.config.ts +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# mongodb-visualizer
|
|
2
|
+
|
|
3
|
+
🚀 **Swagger-like Analyzer for MongoDB (Mongoose) Models**
|
|
4
|
+
|
|
5
|
+
Automatically analyze, visualize, and document your MongoDB models in a Node.js + Express application.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ✨ What is mongodb-visualizer?
|
|
10
|
+
|
|
11
|
+
`mongodb-visualizer` is a developer tool that introspects your **Mongoose models** and provides:
|
|
12
|
+
|
|
13
|
+
- List of all registered models
|
|
14
|
+
- Schema fields with types & validations
|
|
15
|
+
- Model relationships (`ref`)
|
|
16
|
+
- Collection names
|
|
17
|
+
- Optional sample documents
|
|
18
|
+
- Swagger-like web UI
|
|
19
|
+
- JSON APIs for documentation & automation
|
|
20
|
+
|
|
21
|
+
Think of it as **Swagger, but for MongoDB schemas**.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🔧 Supported Stack
|
|
26
|
+
|
|
27
|
+
- Node.js ≥ 16
|
|
28
|
+
- Express ≥ 4
|
|
29
|
+
- Mongoose ≥ 6
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 📦 Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install mongodb-visualizer
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
or
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
yarn add mongodb-visualizer
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 🚀 Quick Start
|
|
46
|
+
|
|
47
|
+
### 1️⃣ Setup Express & Mongoose
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
import express from 'express'
|
|
51
|
+
import mongoose from 'mongoose'
|
|
52
|
+
import { modelAnalyzer } from 'mongodb-visualizer'
|
|
53
|
+
|
|
54
|
+
const app = express()
|
|
55
|
+
|
|
56
|
+
mongoose.connect(process.env.MONGO_URI)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2️⃣ Mount the Analyzer Middleware
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
app.use(
|
|
63
|
+
'/models-analyzer',
|
|
64
|
+
modelAnalyzer({
|
|
65
|
+
mongoose
|
|
66
|
+
})
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3️⃣ Start the Server
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
app.listen(3000, () => {
|
|
74
|
+
console.log('Server running on http://localhost:3000')
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 4️⃣ Open in Browser 🎉
|
|
79
|
+
|
|
80
|
+
Navigate to `http://localhost:3000/models-analyzer`
|
|
81
|
+
|
|
82
|
+
## 📊 API Endpoints
|
|
83
|
+
|
|
84
|
+
### 🔹 Get all models
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
GET /models-analyzer/api/models
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Example Response:**
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
[
|
|
94
|
+
{
|
|
95
|
+
"name": "User",
|
|
96
|
+
"collection": "users",
|
|
97
|
+
"fields": [
|
|
98
|
+
{
|
|
99
|
+
"name": "email",
|
|
100
|
+
"instance": "String",
|
|
101
|
+
"required": true,
|
|
102
|
+
"enum": [],
|
|
103
|
+
"ref": null
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 🔹 Get a single model
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
GET /models-analyzer/api/models/:modelName
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## ⚙️ Configuration Options
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
modelAnalyzer({
|
|
120
|
+
mongoose, // required
|
|
121
|
+
sampleDocs: true, // optional (default: false)
|
|
122
|
+
auth: false // optional (default: false)
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
| Option | Type | Description |
|
|
127
|
+
|--------|------|-------------|
|
|
128
|
+
| mongoose | Object | Mongoose instance |
|
|
129
|
+
| sampleDocs | Boolean | Include sample documents |
|
|
130
|
+
| auth | Boolean | Enable auth middleware |
|
|
131
|
+
|
|
132
|
+
## ## 🔐 Security (Recommended for Production)
|
|
133
|
+
|
|
134
|
+
Do NOT expose this endpoint publicly without authentication.
|
|
135
|
+
|
|
136
|
+
**Example using basic auth:**
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
import basicAuth from 'express-basic-auth'
|
|
140
|
+
|
|
141
|
+
app.use(
|
|
142
|
+
'/models-analyzer',
|
|
143
|
+
basicAuth({
|
|
144
|
+
users: { admin: 'password' },
|
|
145
|
+
challenge: true
|
|
146
|
+
}),
|
|
147
|
+
modelAnalyzer({ mongoose })
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 🧠 How It Works
|
|
152
|
+
|
|
153
|
+
1. Scans all registered Mongoose models
|
|
154
|
+
2. Extracts schema metadata
|
|
155
|
+
3. Parses fields, types, refs, and indexes
|
|
156
|
+
4. Builds structured JSON output
|
|
157
|
+
5. Serves data via API & UI
|
|
158
|
+
|
|
159
|
+
## 🗺️ Roadmap
|
|
160
|
+
|
|
161
|
+
### ✅ v0.1 (Current)
|
|
162
|
+
|
|
163
|
+
- Model scanner
|
|
164
|
+
- Schema parser
|
|
165
|
+
- JSON APIs
|
|
166
|
+
|
|
167
|
+
### 🚀 v0.2
|
|
168
|
+
|
|
169
|
+
- Swagger-like UI
|
|
170
|
+
- Relationship graph
|
|
171
|
+
- Index analyzer
|
|
172
|
+
|
|
173
|
+
### 🧠 v1.0
|
|
174
|
+
|
|
175
|
+
- Performance suggestions
|
|
176
|
+
- Migration hints
|
|
177
|
+
- CLI support
|
|
178
|
+
- Fastify & NestJS adapters
|
|
179
|
+
|
|
180
|
+
## 🤝 Contributing
|
|
181
|
+
|
|
182
|
+
Contributions are welcome!
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
git clone https://github.com/Hibbanur-Rahman/mongodb-visualizer.git
|
|
186
|
+
cd mongodb-visualizer
|
|
187
|
+
npm install
|
|
188
|
+
npm run build
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Feel free to open issues or pull requests 🚀
|
|
192
|
+
|
|
193
|
+
## 📄 License
|
|
194
|
+
|
|
195
|
+
MIT License © 2026
|
|
196
|
+
|
|
197
|
+
## ❤️ Why This Tool?
|
|
198
|
+
|
|
199
|
+
- MongoDB has no built-in schema visualization
|
|
200
|
+
- Helps onboarding new developers
|
|
201
|
+
- Great for documentation & debugging
|
|
202
|
+
- Inspired by Swagger & Prisma Studio
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
**Next steps you can take:**
|
|
207
|
+
- Add npm badges
|
|
208
|
+
- Write a CONTRIBUTING.md
|
|
209
|
+
- Create a docs website
|
|
210
|
+
- Prepare a demo GIF
|
|
211
|
+
|
|
212
|
+
Let me know what's next! 🚀
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
modelAnalyzer: () => modelAnalyzer
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/express/middleware.ts
|
|
38
|
+
var import_express = __toESM(require("express"), 1);
|
|
39
|
+
|
|
40
|
+
// src/core/scanModels.ts
|
|
41
|
+
var import_mongoose = require("mongoose");
|
|
42
|
+
function scanModels(mongoose) {
|
|
43
|
+
return mongoose.modelNames().map((name) => {
|
|
44
|
+
const model = mongoose.model(name);
|
|
45
|
+
return {
|
|
46
|
+
name,
|
|
47
|
+
collection: model.collection.name,
|
|
48
|
+
schema: model.schema
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/core/parseSchema.ts
|
|
54
|
+
var import_mongoose2 = require("mongoose");
|
|
55
|
+
function parseSchema(schema) {
|
|
56
|
+
const fields = [];
|
|
57
|
+
schema.eachPath((path, type) => {
|
|
58
|
+
fields.push({
|
|
59
|
+
name: path,
|
|
60
|
+
instance: type.instance,
|
|
61
|
+
required: !!type.isRequired,
|
|
62
|
+
enum: type.enumValues || [],
|
|
63
|
+
ref: type.options?.ref
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
return fields;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/express/middleware.ts
|
|
70
|
+
function modelAnalyzer(options) {
|
|
71
|
+
const router = import_express.default.Router();
|
|
72
|
+
router.get("/api/models", (req, res) => {
|
|
73
|
+
const models = scanModels(options.mongoose).map((m) => ({
|
|
74
|
+
name: m.name,
|
|
75
|
+
collection: m.collection,
|
|
76
|
+
fields: parseSchema(m.schema)
|
|
77
|
+
}));
|
|
78
|
+
res.json(models);
|
|
79
|
+
});
|
|
80
|
+
return router;
|
|
81
|
+
}
|
|
82
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
83
|
+
0 && (module.exports = {
|
|
84
|
+
modelAnalyzer
|
|
85
|
+
});
|
package/dist/index.d.cts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/express/middleware.ts
|
|
2
|
+
import express from "express";
|
|
3
|
+
|
|
4
|
+
// src/core/scanModels.ts
|
|
5
|
+
import "mongoose";
|
|
6
|
+
function scanModels(mongoose) {
|
|
7
|
+
return mongoose.modelNames().map((name) => {
|
|
8
|
+
const model = mongoose.model(name);
|
|
9
|
+
return {
|
|
10
|
+
name,
|
|
11
|
+
collection: model.collection.name,
|
|
12
|
+
schema: model.schema
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/core/parseSchema.ts
|
|
18
|
+
import "mongoose";
|
|
19
|
+
function parseSchema(schema) {
|
|
20
|
+
const fields = [];
|
|
21
|
+
schema.eachPath((path, type) => {
|
|
22
|
+
fields.push({
|
|
23
|
+
name: path,
|
|
24
|
+
instance: type.instance,
|
|
25
|
+
required: !!type.isRequired,
|
|
26
|
+
enum: type.enumValues || [],
|
|
27
|
+
ref: type.options?.ref
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
return fields;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/express/middleware.ts
|
|
34
|
+
function modelAnalyzer(options) {
|
|
35
|
+
const router = express.Router();
|
|
36
|
+
router.get("/api/models", (req, res) => {
|
|
37
|
+
const models = scanModels(options.mongoose).map((m) => ({
|
|
38
|
+
name: m.name,
|
|
39
|
+
collection: m.collection,
|
|
40
|
+
fields: parseSchema(m.schema)
|
|
41
|
+
}));
|
|
42
|
+
res.json(models);
|
|
43
|
+
});
|
|
44
|
+
return router;
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
modelAnalyzer
|
|
48
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mongodb-models-visualizer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MongoDB Database Visualizer and models relationships between collections",
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"mongoose": ">=6",
|
|
16
|
+
"express": ">=4"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/Hibbanur-Rahman/mongodb-visualizer.git"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [],
|
|
28
|
+
"author": "Hibbanur Rahman",
|
|
29
|
+
"license": "ISC",
|
|
30
|
+
"type": "module",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/Hibbanur-Rahman/mongodb-visualizer/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/Hibbanur-Rahman/mongodb-visualizer#readme",
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/express": "^5.0.6",
|
|
37
|
+
"@types/node": "^25.2.2",
|
|
38
|
+
"tsup": "^8.5.1",
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"express": "^5.2.1",
|
|
43
|
+
"mongoose": "^9.1.6"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Schema } from 'mongoose'
|
|
2
|
+
|
|
3
|
+
export function parseSchema(schema: Schema) {
|
|
4
|
+
const fields: any[] = []
|
|
5
|
+
|
|
6
|
+
schema.eachPath((path, type: any) => {
|
|
7
|
+
fields.push({
|
|
8
|
+
name: path,
|
|
9
|
+
instance: type.instance,
|
|
10
|
+
required: !!type.isRequired,
|
|
11
|
+
enum: type.enumValues || [],
|
|
12
|
+
ref: type.options?.ref
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
return fields
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Mongoose } from 'mongoose'
|
|
2
|
+
|
|
3
|
+
export function scanModels(mongoose: Mongoose) {
|
|
4
|
+
return mongoose.modelNames().map((name) => {
|
|
5
|
+
const model = mongoose.model(name)
|
|
6
|
+
return {
|
|
7
|
+
name,
|
|
8
|
+
collection: model.collection.name,
|
|
9
|
+
schema: model.schema
|
|
10
|
+
}
|
|
11
|
+
})
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { modelAnalyzer } from './middleware'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import { scanModels } from '../core/scanModels'
|
|
3
|
+
import { parseSchema } from '../core/parseSchema'
|
|
4
|
+
|
|
5
|
+
export function modelAnalyzer(options: {
|
|
6
|
+
mongoose: any
|
|
7
|
+
}) {
|
|
8
|
+
const router = express.Router()
|
|
9
|
+
|
|
10
|
+
router.get('/api/models', (req, res) => {
|
|
11
|
+
const models = scanModels(options.mongoose).map((m) => ({
|
|
12
|
+
name: m.name,
|
|
13
|
+
collection: m.collection,
|
|
14
|
+
fields: parseSchema(m.schema)
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
res.json(models)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
return router
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { modelAnalyzer } from './express'
|
|
File without changes
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
// "rootDir": "./src",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "ESNext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"target": "ES2020",
|
|
13
|
+
"types": [],
|
|
14
|
+
// For nodejs:
|
|
15
|
+
// "lib": ["esnext"],
|
|
16
|
+
// "types": ["node"],
|
|
17
|
+
// and npm install -D @types/node
|
|
18
|
+
|
|
19
|
+
// Other Outputs
|
|
20
|
+
"sourceMap": true,
|
|
21
|
+
"declaration": true,
|
|
22
|
+
"declarationMap": true,
|
|
23
|
+
|
|
24
|
+
// Stricter Typechecking Options
|
|
25
|
+
"noUncheckedIndexedAccess": true,
|
|
26
|
+
"exactOptionalPropertyTypes": true,
|
|
27
|
+
|
|
28
|
+
// Style Options
|
|
29
|
+
// "noImplicitReturns": true,
|
|
30
|
+
// "noImplicitOverride": true,
|
|
31
|
+
// "noUnusedLocals": true,
|
|
32
|
+
// "noUnusedParameters": true,
|
|
33
|
+
// "noFallthroughCasesInSwitch": true,
|
|
34
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
35
|
+
|
|
36
|
+
// Recommended Options
|
|
37
|
+
"strict": true,
|
|
38
|
+
"jsx": "react-jsx",
|
|
39
|
+
"verbatimModuleSyntax": true,
|
|
40
|
+
"isolatedModules": true,
|
|
41
|
+
"noUncheckedSideEffectImports": true,
|
|
42
|
+
"moduleDetection": "force",
|
|
43
|
+
"skipLibCheck": true,
|
|
44
|
+
}
|
|
45
|
+
}
|