Search code examples
mongodbdoctrinehiddeninvisibledbref

Mongo dbref additional fields are invisible in mongoshell. How to display them?


Background: This problem came up with Doctrine ODM, that uses a _doctrine_class_name field in DBRefs that is invisible in the Mongo shell (2.2.2) and caused quite a culprit, when we had to update a record manually.

Example:

mongoshell> use testdb; // for safety
mongoshell> a = DBRef("layout_block", ObjectId("510a71fde1dc610965000005")); // create a dbref
mongoshell> a.hiddenfield = "whatever" // add a field that's normally not there like Doctrine does
mongoshell> a // view it's contents, you won't see hiddenfield
mongoshell> for (k in a) { var val = a[k]; print( k + "(" + typeof(val) + "): " + val ); } // you can see that there's more if you iterate through it
mongoshell> db.testcoll.save({ref: [ a ]}) // you can have it in a collection
mongoshell> db.testcoll.findOne(); // and normally you won't see it

Without an iteration like the third command from below (or MongoVue), you won't ever know there's more in a DBRef if you simply use find(). I have not found any usable modifier for find()(tried: toArray, tojson, printjson, toString, hex, base64, pretty, chatty, verbose, ...).

Has anybody got a method to display DBRef contents verbosely in mongo shell?


Solution

  • The Mongo shell is an extension of Mozilla SpiderMonkey (1.7?) and has pretty bare bones functionality.

    The suggestion from a MongoDB blog post on the shell is to define the following inspect function in .mongorc.js in your home directory

    function inspect(o, i) {
        if (typeof i == "undefined") {
            i = "";
        }
        if (i.length > 50) {
            return "[MAX ITERATIONS]";
        }
        var r = [];
        for (var p in o) {
            var t = typeof o[p];
            r.push(i + "\"" + p + "\" (" + t + ") => " + 
                  (t == "object" ? "object:" + inspect(o[p], i + "  ") : o[p] + ""));
        }
        return r.join(i + "\n");
    }
    

    Additionally you can redefine the DBRef.toString function as something like:

    DBRef.prototype.toString = function () {
        var r = ['"$ref": ' + tojson(this.$ref), '"$id": ' + tojson(this.$id)];
        var o = this;
        for (var p in o) {
            if (p !== '$ref' && p !== '$id') {
                var t = typeof o[p];
                r.push('"' + p + '" (' + t + ') : ' + 
                    (t == 'object' ? 'object: {...}' : o[p] + ''));
            }
        }
        return 'DBRef(' + r.join(', ') + ')';
    };