Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-82427

Improve the mongo shell so that objects containing strings with newlines or tabs render properly

    • Type: Icon: Improvement Improvement
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 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.

            Assignee:
            backlog-query-optimization [DO NOT USE] Backlog - Query Optimization
            Reporter:
            david.storch@mongodb.com David Storch
            Votes:
            2 Vote for this issue
            Watchers:
            9 Start watching this issue

              Created:
              Updated: