Skip to content

Commit c5f8f96

Browse files
committed
Merge branch 'release/9.0.0'
2 parents e0a1112 + debd6ff commit c5f8f96

File tree

5 files changed

+41
-313
lines changed

5 files changed

+41
-313
lines changed

README.md

-3
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@
7070
- [`list-collections`](https://github.com/search?type=code&q=repo%3Afurey%2Fmongodb-lens+%2Fserver%5C.tool%5C%28%5Cs*%27list-collections%27%2C%2F): Explore collections in the current database
7171
- [`list-connections`](https://github.com/search?type=code&q=repo%3Afurey%2Fmongodb-lens+%2Fserver%5C.tool%5C%28%5Cs*%27list-connections%27%2C%2F): View all available MongoDB connection aliases
7272
- [`list-databases`](https://github.com/search?type=code&q=repo%3Afurey%2Fmongodb-lens+%2Fserver%5C.tool%5C%28%5Cs*%27list-databases%27%2C%2F): View all accessible databases
73-
- [`map-reduce`](https://github.com/search?type=code&q=repo%3Afurey%2Fmongodb-lens+%2Fserver%5C.tool%5C%28%5Cs*%27map-reduce%27%2C%2F): Run MapReduce operations for complex data processing
7473
- [`rename-collection`](https://github.com/search?type=code&q=repo%3Afurey%2Fmongodb-lens+%2Fserver%5C.tool%5C%28%5Cs*%27rename-collection%27%2C%2F): Rename existing collections ([requires confirmation](#data-protection-confirmation-for-destructive-operations) when dropping targets)
7574
- [`shard-status`](https://github.com/search?type=code&q=repo%3Afurey%2Fmongodb-lens+%2Fserver%5C.tool%5C%28%5Cs*%27shard-status%27%2C%2F): View sharding configuration for databases and collections
7675
- [`text-search`](https://github.com/search?type=code&q=repo%3Afurey%2Fmongodb-lens+%2Fserver%5C.tool%5C%28%5Cs*%27text-search%27%2C%2F): Perform full-text search across text-indexed fields
@@ -1127,8 +1126,6 @@ With your MCP Client running and connected to MongoDB Lens, try the following ex
11271126

11281127
- _"Switch to sample_geospatial db, then find all shipwrecks within 10km of coordinates [-80.12, 26.46]"_<br>
11291128
<sup>➥ Uses `geo-query` tool</sup>
1130-
- _"Switch to sample_mflix db, then run this map reduce to calculate movie counts by year: map=`'function () { emit(this.year, 1) }'` reduce=`'function (key, values) { return Array.sum(values) }'`"_<br>
1131-
<sup>➥ Uses `map-reduce` tool</sup>
11321129
- _"Switch to sample_analytics db, then execute a transaction to move funds between accounts: \<account ids\>"_<br>
11331130
<sup>➥ Uses `transaction` tool</sup>
11341131
- _"Create a time series collection for sensor readings"_<br>

mongodb-lens.js

+4-75
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { readFileSync, existsSync } from 'fs'
77
import { dirname, join } from 'path'
88
import { fileURLToPath } from 'url'
99
import mongodb from 'mongodb'
10+
import { EJSON } from 'bson'
1011
import { z } from 'zod'
1112
import _ from 'lodash'
1213

@@ -2819,35 +2820,6 @@ const registerTools = (server) => {
28192820
)
28202821
}
28212822

2822-
if (!isDisabled('tools', 'map-reduce')) {
2823-
server.tool(
2824-
'map-reduce',
2825-
'Run Map-Reduce operations (note: Map-Reduce deprecated as of MongoDB 5.0)',
2826-
{
2827-
collection: z.string().min(1).describe('Collection name'),
2828-
map: z.string().describe('Map function as string e.g. "function() { emit(this.field, 1); }"'),
2829-
reduce: z.string().describe('Reduce function as string e.g. "function(key, values) { return Array.sum(values); }"'),
2830-
options: z.string().optional().describe('Options as JSON string (query, limit, etc.)')
2831-
},
2832-
async ({ collection, map, reduce, options }) => {
2833-
return withErrorHandling(async () => {
2834-
log(`Tool: Running Map-Reduce on collection '${collection}'…`)
2835-
const mapFunction = eval(`(${map})`)
2836-
const reduceFunction = eval(`(${reduce})`)
2837-
const parsedOptions = options ? JSON.parse(options) : {}
2838-
const results = await runMapReduce(collection, mapFunction, reduceFunction, parsedOptions)
2839-
log(`Tool: Map-Reduce operation complete.`)
2840-
return {
2841-
content: [{
2842-
type: 'text',
2843-
text: formatMapReduceResults(results)
2844-
}]
2845-
}
2846-
}, `Error running Map-Reduce on collection '${collection}'`)
2847-
}
2848-
)
2849-
}
2850-
28512823
if (!isDisabled('tools', 'watch-changes')) {
28522824
server.tool(
28532825
'watch-changes',
@@ -4177,39 +4149,6 @@ const getDistinctValues = async (collectionName, field, filter = {}) => {
41774149
const isValidFieldName = (field) =>
41784150
typeof field === 'string' && field.length > 0 && !field.startsWith('$')
41794151

4180-
const runMapReduce = async (collectionName, map, reduce, options = {}) => {
4181-
log(`DB Operation: Running Map-Reduce on collection '${collectionName}'…`)
4182-
try {
4183-
await throwIfCollectionNotExists(collectionName)
4184-
const collection = currentDb.collection(collectionName)
4185-
4186-
if (!options.out) options.out = { inline: 1 }
4187-
4188-
const results = await collection.mapReduce(map, reduce, options)
4189-
4190-
if (results && typeof results.toArray === 'function') {
4191-
log(`DB Operation: Map-Reduce operation complete (legacy mode).`)
4192-
return results.toArray()
4193-
} else if (results && Array.isArray(results)) {
4194-
log(`DB Operation: Map-Reduce operation complete (array results).`)
4195-
return results
4196-
} else if (results && options.out && options.out.inline !== 1) {
4197-
log(`DB Operation: Map-Reduce output to collection '${typeof options.out === 'string' ? options.out : JSON.stringify(options.out)}'.`)
4198-
const outCollection = currentDb.collection(
4199-
typeof options.out === 'string' ? options.out : options.out.replace
4200-
)
4201-
memoryCache.collections.delete(currentDbName)
4202-
return outCollection.find().toArray()
4203-
} else {
4204-
log(`DB Operation: Map-Reduce operation complete (unknown format).`)
4205-
return Array.isArray(results) ? results : (results.result || results)
4206-
}
4207-
} catch (error) {
4208-
log(`DB Operation: Map-Reduce operation failed: ${error.message}`)
4209-
throw error
4210-
}
4211-
}
4212-
42134152
const bulkOperations = async (collectionName, operations, ordered = config.tools.bulkOperations.ordered) => {
42144153
log(`DB Operation: Performing bulk operations on collection '${collectionName}'…`)
42154154
try {
@@ -4650,16 +4589,6 @@ const formatUpdateResult = (result) => {
46504589
return output
46514590
}
46524591

4653-
const formatMapReduceResults = (results) => {
4654-
if (!results || !Array.isArray(results)) return 'Map-Reduce results not available'
4655-
let output = `Map-Reduce Results (${results.length} entries):\n`
4656-
for (const result of results) {
4657-
output += `- Key: ${formatValue(result._id)}\n`
4658-
output += ` Value: ${formatValue(result.value)}\n`
4659-
}
4660-
return output
4661-
}
4662-
46634592
const formatBulkResult = (result) => {
46644593
if (!result) return 'Bulk operation results not available'
46654594

@@ -5789,7 +5718,7 @@ const parseEnvValue = (value, defaultValue, path) => {
57895718
const parseJsonString = (jsonString) => {
57905719
if (!jsonString || typeof jsonString !== 'string') return jsonString
57915720
try {
5792-
return JSON.parse(jsonString)
5721+
return EJSON.parse(jsonString, { relaxed: false })
57935722
} catch (error) {
57945723
throw new Error(`Invalid JSON: ${error.message}`)
57955724
}
@@ -5954,7 +5883,7 @@ CAPS:
59545883
- DOC: find/count/insert-doc/update-doc/delete
59555884
- SCH: infer/validate/compare/analyze
59565885
- IDX: create/analyze/optimize
5957-
- AGG: pipeline/mapreduce/distinct
5886+
- AGG: pipeline/distinct
59585887
- PERF: explain/analyze/monitor
59595888
- UTIL: clear-cache/export/validate
59605889
- ADV: text/geo/timeseries/bulk/txn/gridfs/sharding/export
@@ -5966,7 +5895,7 @@ PTRNS:
59665895
- MOD: insert-doc/update-doc/delete-doc/bulk-ops
59675896
- SCH: collection-schema/analyze-schema/compare-schemas
59685897
- OPT: explain-query/analyze-patterns/create-index
5969-
- AGG: aggregate-data/map-reduce
5898+
- AGG: aggregate-data
59705899
- MON: server-status/performance-metrics/watch-changes
59715900
- CACHE: clear-cache{all|specific}
59725901
- CONN: add-alias→connect-mongodb→db-ops→connect-original

mongodb-lens.test.js

-26
Original file line numberDiff line numberDiff line change
@@ -1161,31 +1161,6 @@ const testAggregateDataTool = async () => {
11611161
assert(content.includes('"count":'), 'Count not found')
11621162
}
11631163

1164-
const testMapReduceTool = async () => {
1165-
await useTestDatabase()
1166-
1167-
const mapFunction = 'function() { emit(this.isActive, 1); }'
1168-
const reduceFunction = 'function(key, values) { return Array.sum(values); }'
1169-
1170-
const response = await runLensCommand({
1171-
command: 'mcp.tool.invoke',
1172-
params: {
1173-
name: 'map-reduce',
1174-
args: {
1175-
collection: TEST_COLLECTION_NAME,
1176-
map: mapFunction,
1177-
reduce: reduceFunction,
1178-
options: JSON.stringify({ out: { inline: 1 } })
1179-
}
1180-
}
1181-
})
1182-
1183-
assertToolSuccess(response, 'Map-Reduce Results')
1184-
1185-
const content = response.result.content[0].text
1186-
assert(content.includes('Key:') && content.includes('Value:'), 'Map-reduce key-value pairs not found')
1187-
}
1188-
11891164
const testCreateIndexTool = async () => {
11901165
await useTestDatabase()
11911166

@@ -2412,7 +2387,6 @@ const TEST_GROUPS = [
24122387
name: 'Advanced Tools',
24132388
tests: [
24142389
{ name: 'aggregate-data Tool', fn: testAggregateDataTool },
2415-
{ name: 'map-reduce Tool', fn: testMapReduceTool },
24162390
{ name: 'create-index Tool', fn: testCreateIndexTool },
24172391
{ name: 'drop-index Tool', fn: testDropIndexTool },
24182392
{ name: 'analyze-schema Tool', fn: testAnalyzeSchemaTool },

0 commit comments

Comments
 (0)