-
Type: Improvement
-
Resolution: Unresolved
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
Query Optimization
Multi-line strings render in the way I would expect in the mongo shell when they are scalar values:
> let multilineStr = "two\nlines";
> multilineStr
two
lines
However, when the very same multi-line string is embedded in an object, the newline now appears as "\n":
> let objWithMultilineStr = {f: multilineStr}; > objWithMultilineStr { "f" : "two\nlines" }
This is particularly problematic for engineers working with explain output. The current explain output format embeds an SBE plan printed in a string format. If you use the mongo shell to run explain in the simplest way, you get a pretty useless representation of the plan:
> db.c.find({a: {$elemMatch: {b: 1, c: 1}}}, {"a.b": 1, "a.c": 1}).explain() { "explainVersion" : "2", "queryPlanner" : { ... "slotBasedPlan" : { "slots" : "$$RESULT=s7 env: { s1 = Nothing (nothing), s5 = 1, s6 = 1 }", "stages" : "[2] project [s7 = makeBsonObj(MakeObjSpec([\"_id\", \"a\" = MakeObj([\"b\", \"c\"], Closed, ReturnNothing)], Closed, ReturnNothing), s3)] \n[1] filter {((isArray(s2) && traverseF(s2, lambda(l101.0) { (typeMatch(l101.0, 24) && (traverseF(getField(l101.0, \"b\"), lambda(l102.0) { ((move(l102.0) == s5) ?: false) }, false) && traverseF(getField(l101.0, \"c\"), lambda(l103.0) { ((move(l103.0) == s6) ?: false) }, false))) }, false)) ?: false)} \n[1] scan s3 s4 none none none none none none lowPriority [s2 = a] @\"c4494949-e91d-4678-8c71-f05bceac7c8e\" true false " } }, "rejectedPlans" : [ ] }, ... "ok" : 1 }
One workaround is to run explain in such a way as to extract the contents of the plan string directly, in which case the newlines are replaced correctly:
> db.c.find({a: {$elemMatch: {b: 1, c: 1}}}, {"a.b": 1, "a.c": 1}).explain().queryPlanner.winningPlan.slotBasedPlan.stages [2] project [s7 = makeBsonObj(MakeObjSpec(["_id", "a" = MakeObj(["b", "c"], Closed, ReturnNothing)], Closed, ReturnNothing), s3)] [1] filter {((isArray(s2) && traverseF(s2, lambda(l101.0) { (typeMatch(l101.0, 24) && (traverseF(getField(l101.0, "b"), lambda(l102.0) { ((move(l102.0) == s5) ?: false) }, false) && traverseF(getField(l101.0, "c"), lambda(l103.0) { ((move(l103.0) == s6) ?: false) }, false))) }, false)) ?: false)} [1] scan s3 s4 none none none none none none lowPriority [s2 = a] @"c4494949-e91d-4678-8c71-f05bceac7c8e" true false
There may be other workarounds, like using jq or some other tooling. But ideally the mongo shell would provide a natural solution for query or server developers who need to interpret explain output.
- is related to
-
SERVER-61497 Improve the readability of explain plans in 5.X and above
- Backlog