fix(mongo): stop suggesting extended json keys as fields

This commit is contained in:
Loc Nguyen authored and GitHub committed 2026-09-11 13:25:54 +08:00
1 parent 5ba5813247
commit 7c2db2d142
3 files changed
+66 -2

No files matched your search

@@ -1,3 +1,4 @@
import { mongoExtendedJsonValueType } from "@/lib/mongo/mongoDocumentValues";
import { ACCUMULATORS, COMMON_OPERATORS, EXPRESSION_OPERATORS, PIPELINE_STAGES, PUSH_MODIFIERS, QUERY_OPERATORS, STAGE_OPTION_KEYS, UPDATE_OPERATORS, UPDATE_OPERATOR_LABELS, VALUE_SNIPPETS, mongoOperatorItemType, type MongoOperatorSpec } from "@/lib/mongo/mongoCompletionTables";
/**
@@ -1015,6 +1016,9 @@ function extractActiveCollection(text: string, cursor: number): string | undefin
function collectFieldTypes(value: unknown, prefix: string, out: Map<string, Set<string>>, depth: number) {
if (depth > 4 || value == null || typeof value !== "object") return;
// A wrapper such as {$oid: "..."} is one BSON value. Walking into it would offer
// `_id.$oid`, a path that exists only in transport and matches nothing on the server.
if (mongoExtendedJsonValueType(value)) return;
if (Array.isArray(value)) {
for (const item of value.slice(0, 3)) collectFieldTypes(item, prefix, out, depth + 1);
return;
@@ -1031,7 +1035,7 @@ function describeMongoValueType(value: unknown): string {
if (value == null) return "null";
if (Array.isArray(value)) return "array";
if (value instanceof Date) return "date";
return typeof value === "object" ? "object" : typeof value;
return mongoExtendedJsonValueType(value) ?? (typeof value === "object" ? "object" : typeof value);
}
function quoteMongoFieldName(field: string, prefix: string): string {
@@ -15,7 +15,38 @@ export const MONGO_DOCUMENT_GRID_NULL = `${MONGO_DOCUMENT_GRID_PREFIX}null`;
const MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
const MIN_BSON_INT64 = -9223372036854775808n;
const MAX_BSON_INT64 = 9223372036854775807n;
const MONGO_EXTENDED_JSON_VALUE_KEYS = new Set(["$binary", "$code", "$date", "$dbPointer", "$maxKey", "$minKey", "$numberDecimal", "$numberDouble", "$numberInt", "$numberLong", "$oid", "$regularExpression", "$symbol", "$timestamp", "$undefined", "$uuid"]);
/** Extended JSON wrapper key -> the BSON scalar it stands for. */
const MONGO_EXTENDED_JSON_VALUE_TYPES = new Map([
["$binary", "binary"],
["$code", "javascript"],
["$date", "date"],
["$dbPointer", "dbPointer"],
["$maxKey", "maxKey"],
["$minKey", "minKey"],
["$numberDecimal", "decimal128"],
["$numberDouble", "double"],
["$numberInt", "int32"],
["$numberLong", "int64"],
["$oid", "objectId"],
["$regularExpression", "regex"],
["$symbol", "symbol"],
["$timestamp", "timestamp"],
["$undefined", "undefined"],
["$uuid", "uuid"],
]);
const MONGO_EXTENDED_JSON_VALUE_KEYS = new Set(MONGO_EXTENDED_JSON_VALUE_TYPES.keys());
/**
* The BSON scalar an extended JSON wrapper stands for, or undefined when the value is
* a plain object. `{$oid: "..."}` is how the driver ships an ObjectId over JSON; it is
* one value, not a subdocument with a `$oid` field.
*/
export function mongoExtendedJsonValueType(value: unknown): string | undefined {
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
const keys = Object.keys(value as Record<string, unknown>);
if (keys.length === 2 && keys.includes("$code") && keys.includes("$scope")) return "javascript";
return keys.length === 1 ? MONGO_EXTENDED_JSON_VALUE_TYPES.get(keys[0] ?? "") : undefined;
}
const MONGO_EXTENDED_JSON_NUMERIC_TYPES = new Map([
["$numberInt", "int32"],
["$numberLong", "int64"],