@cli4ai/mongodb 1.0.7 → 1.0.9
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/cli4ai.json +199 -18
- package/dist/run.d.ts +2 -0
- package/dist/run.js +198 -0
- package/package.json +13 -5
- package/run.ts +0 -216
package/cli4ai.json
CHANGED
|
@@ -1,33 +1,214 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongodb",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "MongoDB queries",
|
|
5
5
|
"author": "cliforai",
|
|
6
|
-
"license": "
|
|
7
|
-
"entry": "run.
|
|
6
|
+
"license": "BUSL-1.1",
|
|
7
|
+
"entry": "dist/run.js",
|
|
8
8
|
"runtime": "node",
|
|
9
|
-
"keywords": [
|
|
9
|
+
"keywords": [
|
|
10
|
+
"mongodb",
|
|
11
|
+
"database",
|
|
12
|
+
"nosql",
|
|
13
|
+
"query"
|
|
14
|
+
],
|
|
10
15
|
"commands": {
|
|
11
|
-
"databases": {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
"databases": {
|
|
17
|
+
"description": "List all databases"
|
|
18
|
+
},
|
|
19
|
+
"collections": {
|
|
20
|
+
"description": "List collections",
|
|
21
|
+
"args": [
|
|
22
|
+
{
|
|
23
|
+
"name": "db",
|
|
24
|
+
"required": true
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"schema": {
|
|
29
|
+
"description": "Infer schema",
|
|
30
|
+
"args": [
|
|
31
|
+
{
|
|
32
|
+
"name": "db",
|
|
33
|
+
"required": true
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "collection",
|
|
37
|
+
"required": true
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "samples",
|
|
41
|
+
"required": false
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"find": {
|
|
46
|
+
"description": "Find documents",
|
|
47
|
+
"args": [
|
|
48
|
+
{
|
|
49
|
+
"name": "db",
|
|
50
|
+
"required": true
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "collection",
|
|
54
|
+
"required": true
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "query",
|
|
58
|
+
"required": false
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "limit",
|
|
62
|
+
"required": false
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"one": {
|
|
67
|
+
"description": "Single document",
|
|
68
|
+
"args": [
|
|
69
|
+
{
|
|
70
|
+
"name": "db",
|
|
71
|
+
"required": true
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "collection",
|
|
75
|
+
"required": true
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "query",
|
|
79
|
+
"required": false
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"aggregate": {
|
|
84
|
+
"description": "Run aggregation pipeline",
|
|
85
|
+
"args": [
|
|
86
|
+
{
|
|
87
|
+
"name": "db",
|
|
88
|
+
"required": true
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "collection",
|
|
92
|
+
"required": true
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "pipeline",
|
|
96
|
+
"required": true
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
"count": {
|
|
101
|
+
"description": "Count documents",
|
|
102
|
+
"args": [
|
|
103
|
+
{
|
|
104
|
+
"name": "db",
|
|
105
|
+
"required": true
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "collection",
|
|
109
|
+
"required": true
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "query",
|
|
113
|
+
"required": false
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"indexes": {
|
|
118
|
+
"description": "List indexes",
|
|
119
|
+
"args": [
|
|
120
|
+
{
|
|
121
|
+
"name": "db",
|
|
122
|
+
"required": true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "collection",
|
|
126
|
+
"required": true
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
"stats": {
|
|
131
|
+
"description": "Collection statistics",
|
|
132
|
+
"args": [
|
|
133
|
+
{
|
|
134
|
+
"name": "db",
|
|
135
|
+
"required": true
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"name": "collection",
|
|
139
|
+
"required": true
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
"distinct": {
|
|
144
|
+
"description": "Distinct values",
|
|
145
|
+
"args": [
|
|
146
|
+
{
|
|
147
|
+
"name": "db",
|
|
148
|
+
"required": true
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "collection",
|
|
152
|
+
"required": true
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"name": "field",
|
|
156
|
+
"required": true
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"name": "query",
|
|
160
|
+
"required": false
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
"sample": {
|
|
165
|
+
"description": "Random sample",
|
|
166
|
+
"args": [
|
|
167
|
+
{
|
|
168
|
+
"name": "db",
|
|
169
|
+
"required": true
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"name": "collection",
|
|
173
|
+
"required": true
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"name": "size",
|
|
177
|
+
"required": false
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
"explain": {
|
|
182
|
+
"description": "Query explanation",
|
|
183
|
+
"args": [
|
|
184
|
+
{
|
|
185
|
+
"name": "db",
|
|
186
|
+
"required": true
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "collection",
|
|
190
|
+
"required": true
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"name": "query",
|
|
194
|
+
"required": false
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
}
|
|
23
198
|
},
|
|
24
199
|
"env": {
|
|
25
|
-
"MONGO_URI": {
|
|
200
|
+
"MONGO_URI": {
|
|
201
|
+
"required": false,
|
|
202
|
+
"description": "MongoDB connection URI (default: localhost:27017)"
|
|
203
|
+
}
|
|
26
204
|
},
|
|
27
205
|
"dependencies": {
|
|
28
206
|
"@cli4ai/lib": "^1.0.0",
|
|
29
207
|
"mongodb": "^6.0.0",
|
|
30
208
|
"commander": "^14.0.0"
|
|
31
209
|
},
|
|
32
|
-
"mcp": {
|
|
210
|
+
"mcp": {
|
|
211
|
+
"enabled": true,
|
|
212
|
+
"transport": "stdio"
|
|
213
|
+
}
|
|
33
214
|
}
|
package/dist/run.d.ts
ADDED
package/dist/run.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { MongoClient } from 'mongodb';
|
|
3
|
+
import { cli, loadEnv, output, withErrorHandling, parseJson } from '@cli4ai/lib';
|
|
4
|
+
loadEnv();
|
|
5
|
+
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017';
|
|
6
|
+
async function withClient(fn) {
|
|
7
|
+
const client = new MongoClient(MONGO_URI);
|
|
8
|
+
try {
|
|
9
|
+
await client.connect();
|
|
10
|
+
return await fn(client);
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
await client.close();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Infer schema from documents by analyzing field types
|
|
17
|
+
function inferSchema(docs) {
|
|
18
|
+
const schema = {};
|
|
19
|
+
function getType(value) {
|
|
20
|
+
if (value === null)
|
|
21
|
+
return 'null';
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return 'array';
|
|
24
|
+
if (value instanceof Date)
|
|
25
|
+
return 'date';
|
|
26
|
+
if (typeof value === 'object' && value.constructor?.name === 'ObjectId')
|
|
27
|
+
return 'ObjectId';
|
|
28
|
+
if (typeof value === 'object' && value.constructor?.name === 'Binary')
|
|
29
|
+
return 'Binary';
|
|
30
|
+
return typeof value;
|
|
31
|
+
}
|
|
32
|
+
function processDoc(doc, prefix = '') {
|
|
33
|
+
for (const [key, value] of Object.entries(doc)) {
|
|
34
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
35
|
+
const type = getType(value);
|
|
36
|
+
if (!schema[path]) {
|
|
37
|
+
schema[path] = { types: new Set(), sample: value, count: 0 };
|
|
38
|
+
}
|
|
39
|
+
schema[path].types.add(type);
|
|
40
|
+
schema[path].count++;
|
|
41
|
+
// Recurse into objects (but not arrays or special types)
|
|
42
|
+
if (type === 'object' && value !== null) {
|
|
43
|
+
processDoc(value, path);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
docs.forEach(doc => processDoc(doc));
|
|
48
|
+
// Convert to output format
|
|
49
|
+
const result = {};
|
|
50
|
+
for (const [path, info] of Object.entries(schema)) {
|
|
51
|
+
result[path] = {
|
|
52
|
+
types: Array.from(info.types),
|
|
53
|
+
sample: info.sample,
|
|
54
|
+
frequency: `${info.count}/${docs.length}`
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
const program = cli('mongodb', '1.0.0', 'MongoDB queries');
|
|
60
|
+
program
|
|
61
|
+
.command('databases')
|
|
62
|
+
.description('List all databases')
|
|
63
|
+
.action(withErrorHandling(async () => {
|
|
64
|
+
await withClient(async (client) => {
|
|
65
|
+
const admin = client.db().admin();
|
|
66
|
+
const result = await admin.listDatabases();
|
|
67
|
+
output(result.databases.map(db => ({
|
|
68
|
+
name: db.name,
|
|
69
|
+
sizeOnDisk: db.sizeOnDisk,
|
|
70
|
+
sizeMB: db.sizeOnDisk ? Math.round(db.sizeOnDisk / 1024 / 1024 * 100) / 100 : 0
|
|
71
|
+
})));
|
|
72
|
+
});
|
|
73
|
+
}));
|
|
74
|
+
program
|
|
75
|
+
.command('collections <db>')
|
|
76
|
+
.description('List collections')
|
|
77
|
+
.action(withErrorHandling(async (dbName) => {
|
|
78
|
+
await withClient(async (client) => {
|
|
79
|
+
const db = client.db(dbName);
|
|
80
|
+
const collections = await db.listCollections().toArray();
|
|
81
|
+
output(collections.map(c => ({ name: c.name, type: c.type })));
|
|
82
|
+
});
|
|
83
|
+
}));
|
|
84
|
+
program
|
|
85
|
+
.command('schema <db> <collection> [samples]')
|
|
86
|
+
.description('Infer schema (default: 100 samples)')
|
|
87
|
+
.action(withErrorHandling(async (dbName, collName, sampleSize = '100') => {
|
|
88
|
+
await withClient(async (client) => {
|
|
89
|
+
const collection = client.db(dbName).collection(collName);
|
|
90
|
+
const docs = await collection.find({}).limit(parseInt(sampleSize)).toArray();
|
|
91
|
+
const schema = inferSchema(docs);
|
|
92
|
+
output({
|
|
93
|
+
collection: `${dbName}.${collName}`,
|
|
94
|
+
sampledDocs: docs.length,
|
|
95
|
+
fields: schema
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}));
|
|
99
|
+
program
|
|
100
|
+
.command('find <db> <collection> [query] [limit]')
|
|
101
|
+
.description('Find documents (default: {}, 10)')
|
|
102
|
+
.action(withErrorHandling(async (dbName, collName, query = '{}', limit = '10') => {
|
|
103
|
+
await withClient(async (client) => {
|
|
104
|
+
const collection = client.db(dbName).collection(collName);
|
|
105
|
+
const docs = await collection.find(parseJson(query, 'query')).limit(parseInt(limit)).toArray();
|
|
106
|
+
output(docs);
|
|
107
|
+
});
|
|
108
|
+
}));
|
|
109
|
+
program
|
|
110
|
+
.command('one <db> <collection> [query]')
|
|
111
|
+
.description('Single document')
|
|
112
|
+
.action(withErrorHandling(async (dbName, collName, query = '{}') => {
|
|
113
|
+
await withClient(async (client) => {
|
|
114
|
+
const collection = client.db(dbName).collection(collName);
|
|
115
|
+
const doc = await collection.findOne(parseJson(query, 'query'));
|
|
116
|
+
output(doc);
|
|
117
|
+
});
|
|
118
|
+
}));
|
|
119
|
+
program
|
|
120
|
+
.command('aggregate <db> <collection> <pipeline>')
|
|
121
|
+
.description('Run aggregation pipeline')
|
|
122
|
+
.action(withErrorHandling(async (dbName, collName, pipeline) => {
|
|
123
|
+
await withClient(async (client) => {
|
|
124
|
+
const collection = client.db(dbName).collection(collName);
|
|
125
|
+
const docs = await collection.aggregate(parseJson(pipeline, 'pipeline')).toArray();
|
|
126
|
+
output(docs);
|
|
127
|
+
});
|
|
128
|
+
}));
|
|
129
|
+
program
|
|
130
|
+
.command('count <db> <collection> [query]')
|
|
131
|
+
.description('Count documents')
|
|
132
|
+
.action(withErrorHandling(async (dbName, collName, query = '{}') => {
|
|
133
|
+
await withClient(async (client) => {
|
|
134
|
+
const collection = client.db(dbName).collection(collName);
|
|
135
|
+
const count = await collection.countDocuments(parseJson(query, 'query'));
|
|
136
|
+
output({ collection: `${dbName}.${collName}`, count });
|
|
137
|
+
});
|
|
138
|
+
}));
|
|
139
|
+
program
|
|
140
|
+
.command('indexes <db> <collection>')
|
|
141
|
+
.description('List indexes')
|
|
142
|
+
.action(withErrorHandling(async (dbName, collName) => {
|
|
143
|
+
await withClient(async (client) => {
|
|
144
|
+
const collection = client.db(dbName).collection(collName);
|
|
145
|
+
const indexes = await collection.indexes();
|
|
146
|
+
output(indexes);
|
|
147
|
+
});
|
|
148
|
+
}));
|
|
149
|
+
program
|
|
150
|
+
.command('stats <db> <collection>')
|
|
151
|
+
.description('Collection statistics')
|
|
152
|
+
.action(withErrorHandling(async (dbName, collName) => {
|
|
153
|
+
await withClient(async (client) => {
|
|
154
|
+
const db = client.db(dbName);
|
|
155
|
+
const stats = await db.command({ collStats: collName });
|
|
156
|
+
output({
|
|
157
|
+
ns: stats.ns,
|
|
158
|
+
count: stats.count,
|
|
159
|
+
size: stats.size,
|
|
160
|
+
sizeMB: Math.round(stats.size / 1024 / 1024 * 100) / 100,
|
|
161
|
+
avgObjSize: stats.avgObjSize,
|
|
162
|
+
storageSize: stats.storageSize,
|
|
163
|
+
indexes: stats.nindexes,
|
|
164
|
+
indexSize: stats.totalIndexSize
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}));
|
|
168
|
+
program
|
|
169
|
+
.command('distinct <db> <collection> <field> [query]')
|
|
170
|
+
.description('Distinct values')
|
|
171
|
+
.action(withErrorHandling(async (dbName, collName, field, query = '{}') => {
|
|
172
|
+
await withClient(async (client) => {
|
|
173
|
+
const collection = client.db(dbName).collection(collName);
|
|
174
|
+
const values = await collection.distinct(field, parseJson(query, 'query'));
|
|
175
|
+
output({ field, count: values.length, values });
|
|
176
|
+
});
|
|
177
|
+
}));
|
|
178
|
+
program
|
|
179
|
+
.command('sample <db> <collection> [size]')
|
|
180
|
+
.description('Random sample (default: 5)')
|
|
181
|
+
.action(withErrorHandling(async (dbName, collName, size = '5') => {
|
|
182
|
+
await withClient(async (client) => {
|
|
183
|
+
const collection = client.db(dbName).collection(collName);
|
|
184
|
+
const docs = await collection.aggregate([{ $sample: { size: parseInt(size) } }]).toArray();
|
|
185
|
+
output(docs);
|
|
186
|
+
});
|
|
187
|
+
}));
|
|
188
|
+
program
|
|
189
|
+
.command('explain <db> <collection> [query]')
|
|
190
|
+
.description('Query explanation')
|
|
191
|
+
.action(withErrorHandling(async (dbName, collName, query = '{}') => {
|
|
192
|
+
await withClient(async (client) => {
|
|
193
|
+
const collection = client.db(dbName).collection(collName);
|
|
194
|
+
const explanation = await collection.find(parseJson(query, 'query')).explain('executionStats');
|
|
195
|
+
output(explanation);
|
|
196
|
+
});
|
|
197
|
+
}));
|
|
198
|
+
program.parse();
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cli4ai/mongodb",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "MongoDB queries",
|
|
5
5
|
"author": "cliforai",
|
|
6
|
-
"license": "
|
|
7
|
-
"main": "run.
|
|
6
|
+
"license": "BUSL-1.1",
|
|
7
|
+
"main": "dist/run.js",
|
|
8
8
|
"bin": {
|
|
9
|
-
"mongodb": "./run.
|
|
9
|
+
"mongodb": "./dist/run.js"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
12
|
"keywords": [
|
|
@@ -33,12 +33,20 @@
|
|
|
33
33
|
"commander": "^14.0.0"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
|
-
"
|
|
36
|
+
"dist",
|
|
37
37
|
"cli4ai.json",
|
|
38
38
|
"README.md",
|
|
39
39
|
"LICENSE"
|
|
40
40
|
],
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"prepublishOnly": "npm run build"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"typescript": "^5.0.0",
|
|
50
|
+
"@types/node": "^22.0.0"
|
|
43
51
|
}
|
|
44
52
|
}
|
package/run.ts
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env npx tsx
|
|
2
|
-
import { MongoClient, Document } from 'mongodb';
|
|
3
|
-
import { cli, loadEnv, output, outputError, withErrorHandling, parseJson } from '@cli4ai/lib/cli.ts';
|
|
4
|
-
|
|
5
|
-
loadEnv();
|
|
6
|
-
|
|
7
|
-
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017';
|
|
8
|
-
|
|
9
|
-
async function withClient<T>(fn: (client: MongoClient) => Promise<T>): Promise<T> {
|
|
10
|
-
const client = new MongoClient(MONGO_URI);
|
|
11
|
-
try {
|
|
12
|
-
await client.connect();
|
|
13
|
-
return await fn(client);
|
|
14
|
-
} finally {
|
|
15
|
-
await client.close();
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Infer schema from documents by analyzing field types
|
|
20
|
-
function inferSchema(docs: Document[]): Document {
|
|
21
|
-
const schema: Record<string, { types: Set<string>; sample: unknown; count: number }> = {};
|
|
22
|
-
|
|
23
|
-
function getType(value: unknown): string {
|
|
24
|
-
if (value === null) return 'null';
|
|
25
|
-
if (Array.isArray(value)) return 'array';
|
|
26
|
-
if (value instanceof Date) return 'date';
|
|
27
|
-
if (typeof value === 'object' && (value as object).constructor?.name === 'ObjectId') return 'ObjectId';
|
|
28
|
-
if (typeof value === 'object' && (value as object).constructor?.name === 'Binary') return 'Binary';
|
|
29
|
-
return typeof value;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function processDoc(doc: Document, prefix = ''): void {
|
|
33
|
-
for (const [key, value] of Object.entries(doc)) {
|
|
34
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
35
|
-
const type = getType(value);
|
|
36
|
-
|
|
37
|
-
if (!schema[path]) {
|
|
38
|
-
schema[path] = { types: new Set(), sample: value, count: 0 };
|
|
39
|
-
}
|
|
40
|
-
schema[path].types.add(type);
|
|
41
|
-
schema[path].count++;
|
|
42
|
-
|
|
43
|
-
// Recurse into objects (but not arrays or special types)
|
|
44
|
-
if (type === 'object' && value !== null) {
|
|
45
|
-
processDoc(value as Document, path);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
docs.forEach(doc => processDoc(doc));
|
|
51
|
-
|
|
52
|
-
// Convert to output format
|
|
53
|
-
const result: Record<string, { types: string[]; sample: unknown; frequency: string }> = {};
|
|
54
|
-
for (const [path, info] of Object.entries(schema)) {
|
|
55
|
-
result[path] = {
|
|
56
|
-
types: Array.from(info.types),
|
|
57
|
-
sample: info.sample,
|
|
58
|
-
frequency: `${info.count}/${docs.length}`
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const program = cli('mongodb', '1.0.0', 'MongoDB queries');
|
|
65
|
-
|
|
66
|
-
program
|
|
67
|
-
.command('databases')
|
|
68
|
-
.description('List all databases')
|
|
69
|
-
.action(withErrorHandling(async () => {
|
|
70
|
-
await withClient(async (client) => {
|
|
71
|
-
const admin = client.db().admin();
|
|
72
|
-
const result = await admin.listDatabases();
|
|
73
|
-
output(result.databases.map(db => ({
|
|
74
|
-
name: db.name,
|
|
75
|
-
sizeOnDisk: db.sizeOnDisk,
|
|
76
|
-
sizeMB: db.sizeOnDisk ? Math.round(db.sizeOnDisk / 1024 / 1024 * 100) / 100 : 0
|
|
77
|
-
})));
|
|
78
|
-
});
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
|
-
program
|
|
82
|
-
.command('collections <db>')
|
|
83
|
-
.description('List collections')
|
|
84
|
-
.action(withErrorHandling(async (dbName: string) => {
|
|
85
|
-
await withClient(async (client) => {
|
|
86
|
-
const db = client.db(dbName);
|
|
87
|
-
const collections = await db.listCollections().toArray();
|
|
88
|
-
output(collections.map(c => ({ name: c.name, type: c.type })));
|
|
89
|
-
});
|
|
90
|
-
}));
|
|
91
|
-
|
|
92
|
-
program
|
|
93
|
-
.command('schema <db> <collection> [samples]')
|
|
94
|
-
.description('Infer schema (default: 100 samples)')
|
|
95
|
-
.action(withErrorHandling(async (dbName: string, collName: string, sampleSize = '100') => {
|
|
96
|
-
await withClient(async (client) => {
|
|
97
|
-
const collection = client.db(dbName).collection(collName);
|
|
98
|
-
const docs = await collection.find({}).limit(parseInt(sampleSize)).toArray();
|
|
99
|
-
const schema = inferSchema(docs);
|
|
100
|
-
output({
|
|
101
|
-
collection: `${dbName}.${collName}`,
|
|
102
|
-
sampledDocs: docs.length,
|
|
103
|
-
fields: schema
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
}));
|
|
107
|
-
|
|
108
|
-
program
|
|
109
|
-
.command('find <db> <collection> [query] [limit]')
|
|
110
|
-
.description('Find documents (default: {}, 10)')
|
|
111
|
-
.action(withErrorHandling(async (dbName: string, collName: string, query = '{}', limit = '10') => {
|
|
112
|
-
await withClient(async (client) => {
|
|
113
|
-
const collection = client.db(dbName).collection(collName);
|
|
114
|
-
const docs = await collection.find(parseJson(query, 'query')).limit(parseInt(limit)).toArray();
|
|
115
|
-
output(docs);
|
|
116
|
-
});
|
|
117
|
-
}));
|
|
118
|
-
|
|
119
|
-
program
|
|
120
|
-
.command('one <db> <collection> [query]')
|
|
121
|
-
.description('Single document')
|
|
122
|
-
.action(withErrorHandling(async (dbName: string, collName: string, query = '{}') => {
|
|
123
|
-
await withClient(async (client) => {
|
|
124
|
-
const collection = client.db(dbName).collection(collName);
|
|
125
|
-
const doc = await collection.findOne(parseJson(query, 'query'));
|
|
126
|
-
output(doc);
|
|
127
|
-
});
|
|
128
|
-
}));
|
|
129
|
-
|
|
130
|
-
program
|
|
131
|
-
.command('aggregate <db> <collection> <pipeline>')
|
|
132
|
-
.description('Run aggregation pipeline')
|
|
133
|
-
.action(withErrorHandling(async (dbName: string, collName: string, pipeline: string) => {
|
|
134
|
-
await withClient(async (client) => {
|
|
135
|
-
const collection = client.db(dbName).collection(collName);
|
|
136
|
-
const docs = await collection.aggregate(parseJson(pipeline, 'pipeline')).toArray();
|
|
137
|
-
output(docs);
|
|
138
|
-
});
|
|
139
|
-
}));
|
|
140
|
-
|
|
141
|
-
program
|
|
142
|
-
.command('count <db> <collection> [query]')
|
|
143
|
-
.description('Count documents')
|
|
144
|
-
.action(withErrorHandling(async (dbName: string, collName: string, query = '{}') => {
|
|
145
|
-
await withClient(async (client) => {
|
|
146
|
-
const collection = client.db(dbName).collection(collName);
|
|
147
|
-
const count = await collection.countDocuments(parseJson(query, 'query'));
|
|
148
|
-
output({ collection: `${dbName}.${collName}`, count });
|
|
149
|
-
});
|
|
150
|
-
}));
|
|
151
|
-
|
|
152
|
-
program
|
|
153
|
-
.command('indexes <db> <collection>')
|
|
154
|
-
.description('List indexes')
|
|
155
|
-
.action(withErrorHandling(async (dbName: string, collName: string) => {
|
|
156
|
-
await withClient(async (client) => {
|
|
157
|
-
const collection = client.db(dbName).collection(collName);
|
|
158
|
-
const indexes = await collection.indexes();
|
|
159
|
-
output(indexes);
|
|
160
|
-
});
|
|
161
|
-
}));
|
|
162
|
-
|
|
163
|
-
program
|
|
164
|
-
.command('stats <db> <collection>')
|
|
165
|
-
.description('Collection statistics')
|
|
166
|
-
.action(withErrorHandling(async (dbName: string, collName: string) => {
|
|
167
|
-
await withClient(async (client) => {
|
|
168
|
-
const db = client.db(dbName);
|
|
169
|
-
const stats = await db.command({ collStats: collName });
|
|
170
|
-
output({
|
|
171
|
-
ns: stats.ns,
|
|
172
|
-
count: stats.count,
|
|
173
|
-
size: stats.size,
|
|
174
|
-
sizeMB: Math.round(stats.size / 1024 / 1024 * 100) / 100,
|
|
175
|
-
avgObjSize: stats.avgObjSize,
|
|
176
|
-
storageSize: stats.storageSize,
|
|
177
|
-
indexes: stats.nindexes,
|
|
178
|
-
indexSize: stats.totalIndexSize
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
}));
|
|
182
|
-
|
|
183
|
-
program
|
|
184
|
-
.command('distinct <db> <collection> <field> [query]')
|
|
185
|
-
.description('Distinct values')
|
|
186
|
-
.action(withErrorHandling(async (dbName: string, collName: string, field: string, query = '{}') => {
|
|
187
|
-
await withClient(async (client) => {
|
|
188
|
-
const collection = client.db(dbName).collection(collName);
|
|
189
|
-
const values = await collection.distinct(field, parseJson(query, 'query'));
|
|
190
|
-
output({ field, count: values.length, values });
|
|
191
|
-
});
|
|
192
|
-
}));
|
|
193
|
-
|
|
194
|
-
program
|
|
195
|
-
.command('sample <db> <collection> [size]')
|
|
196
|
-
.description('Random sample (default: 5)')
|
|
197
|
-
.action(withErrorHandling(async (dbName: string, collName: string, size = '5') => {
|
|
198
|
-
await withClient(async (client) => {
|
|
199
|
-
const collection = client.db(dbName).collection(collName);
|
|
200
|
-
const docs = await collection.aggregate([{ $sample: { size: parseInt(size) } }]).toArray();
|
|
201
|
-
output(docs);
|
|
202
|
-
});
|
|
203
|
-
}));
|
|
204
|
-
|
|
205
|
-
program
|
|
206
|
-
.command('explain <db> <collection> [query]')
|
|
207
|
-
.description('Query explanation')
|
|
208
|
-
.action(withErrorHandling(async (dbName: string, collName: string, query = '{}') => {
|
|
209
|
-
await withClient(async (client) => {
|
|
210
|
-
const collection = client.db(dbName).collection(collName);
|
|
211
|
-
const explanation = await collection.find(parseJson(query, 'query')).explain('executionStats');
|
|
212
|
-
output(explanation);
|
|
213
|
-
});
|
|
214
|
-
}));
|
|
215
|
-
|
|
216
|
-
program.parse();
|