From 5a47084c7ba5b0ccd316fcaa73235a3ab0fe1fa1 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 24 Jul 2026 14:30:34 +0800 Subject: [PATCH] fix(mongodb): decode extended JSON document ids --- .../com/dbx/agent/mongodb/MongoAgent.java | 39 ++++++++++++------- .../com/dbx/agent/mongodb/MongoAgentTest.java | 19 +++++++++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java b/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java index a8ce75a44..dc2d92eb9 100644 --- a/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java +++ b/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java @@ -641,12 +641,9 @@ public final class MongoAgent { return stringId; } String trimmed = id.trim(); - if (isNumberLongIdWrapper(trimmed)) { - try { - return Document.parse("{\"_id\":" + trimmed + "}").get("_id"); - } catch (Exception e) { - // Fall through to the legacy ObjectId/string handling below. - } + Object extendedJsonId = parseExtendedJsonId(trimmed); + if (extendedJsonId != null) { + return extendedJsonId; } try { return new ObjectId(id); @@ -668,20 +665,21 @@ public final class MongoAgent { } } - private static boolean isNumberLongIdWrapper(String value) { + private static Object parseExtendedJsonId(String value) { try { JsonElement parsed = JsonParser.parseString(value); if (!parsed.isJsonObject()) { - return false; + return null; } JsonObject wrapper = parsed.getAsJsonObject(); - JsonElement numberLong = wrapper.get("$numberLong"); - return wrapper.size() == 1 - && numberLong != null - && numberLong.isJsonPrimitive() - && numberLong.getAsJsonPrimitive().isString(); + if (wrapper.size() != 1 || (!wrapper.has("$oid") && !wrapper.has("$numberLong"))) { + return null; + } + // The document browser preserves BSON _id types as Extended JSON; + // decode only known wrappers so JSON-looking string IDs stay strings. + return Document.parse("{\"_id\":" + value + "}").get("_id"); } catch (Exception e) { - return false; + return null; } } @@ -698,9 +696,22 @@ public final class MongoAgent { var result = isUpdateOperatorDocument(newDoc) ? col.updateOne(filter, newDoc) : col.replaceOne(filter, replacementDocument(newDoc)); + requireMatchedDocument(id, result); return Collections.singletonMap("modified_count", result.getModifiedCount()); } + static void requireMatchedDocument(String id, UpdateResult result) { + if (result.getMatchedCount() == 0) { + throw new IllegalStateException(noMatchingDocumentError(id)); + } + } + + private static String noMatchingDocumentError(String id) { + String display = decodeStringDocumentId(id); + return "No document matched _id " + (display == null ? id : display) + + ". It may have been deleted or its _id changed since the query ran."; + } + private static Object updateDocuments(JsonObject params) { MongoClient c = requireClient(); String database = params.get("database").getAsString(); diff --git a/agents/drivers/mongodb/src/test/java/com/dbx/agent/mongodb/MongoAgentTest.java b/agents/drivers/mongodb/src/test/java/com/dbx/agent/mongodb/MongoAgentTest.java index 6e5165784..4bb1df5ed 100644 --- a/agents/drivers/mongodb/src/test/java/com/dbx/agent/mongodb/MongoAgentTest.java +++ b/agents/drivers/mongodb/src/test/java/com/dbx/agent/mongodb/MongoAgentTest.java @@ -179,10 +179,12 @@ class MongoAgentTest { void preservesLongDocumentIdTypeForGridUpdates() { Object id = MongoAgent.convertDocumentFieldValue("_id", 2_048_938_405_781_032_962L); Object value = MongoAgent.convertDocumentFieldValue("snowflake", 2_048_938_405_781_032_962L); + ObjectId objectId = new ObjectId("507f1f77bcf86cd799439011"); assertEquals(Collections.singletonMap("$numberLong", "2048938405781032962"), id); assertEquals("2048938405781032962", value); assertEquals(2_048_938_405_781_032_962L, MongoAgent.parseId("{\"$numberLong\":\"2048938405781032962\"}")); + assertEquals(objectId, MongoAgent.parseId("{\"$oid\":\"507f1f77bcf86cd799439011\"}")); } @Test @@ -196,6 +198,23 @@ class MongoAgentTest { assertEquals("{\"$numberLong\":\"invalid\"}", MongoAgent.parseId("{\"$numberLong\":\"invalid\"}")); } + @Test + void documentUpdateDistinguishesNoMatchFromUnchangedValue() { + MongoAgent.requireMatchedDocument( + "{\"$oid\":\"507f1f77bcf86cd799439011\"}", + UpdateResult.acknowledged(1, 0L, null) + ); + + IllegalStateException error = assertThrows( + IllegalStateException.class, + () -> MongoAgent.requireMatchedDocument( + "{\"$oid\":\"507f1f77bcf86cd799439012\"}", + UpdateResult.acknowledged(0, 0L, null) + ) + ); + assertTrue(error.getMessage().startsWith("No document matched _id")); + } + @Test void serverVersionMethodIsRecognizedOverJsonRpc() { String response = MongoAgent.handleRequest(