NoSQL Zone is brought to you in partnership with:

Daniel Doubrovkine (aka dB.) is one of the tallest engineers at Art.sy. He founded and exited a successful Swiss start-up in the 90s, worked for Microsoft Corp. in Redmond, specializing in security and authentication, dabbled in large scale social networking and ran a big team that developed an expensive Enterprise product in NYC. After turning open-source cheerleader a few years ago in the worlds of C++, Java and .NET, he converted himself to Ruby and has been slowly unlearning everything he learned in the last 15 years of software practice. Daniel has posted 46 posts at DZone. You can read more from them at their website. View Full User Profile

Debugging “object has no properties” in a MongoDB map/reduce

11.30.2012
| 3915 views |
  • submit to reddit

You got to love debugging JavaScript errors. Here’s one from a MongoDB map/reduce. The operation fails with this:

    04:39:41  Database command 'mapreduce' failed: (
        assertion: 'map invoke failed: JS Error:
            TypeError: spline has no properties nofile_b:7';
        assertionCode: '9014';
        errmsg: 'db assertion failure';
        ok: '0.0').

Examining the MongoDB log we notice that the map/reduce completes to about 70%, so this is caused by some data inside the database. In this case the issue is in the spline object being accessed by the map function. Indeed, the map tries to fetch spline.reticulated, which is hopefully a Boolean value. The error “spline has no properties” is, generally, another way of saying “spline is null”. In my case splines live in an embedded collection inside bones, and aren’t expected to be null, so I need to track down a null spline inside bone.splines.

While we can just look for a null embedded object, more generally, we can find whether a JS object has no properties with this isEmpty function from SO. Declare it in the mongodb console (use a 1-liner):

    function isEmpty(map) {
        for(var key in map) {
            if (map.hasOwnProperty(key)) {
                return false;
            }
        }
        return true;
    }

Iterate over all bones records.

    db.bones.find().forEach(function(bone) {
        if (bone.splines) {
            bone.splines.forEach(function(spline) {
                if (isEmpty(spline)) {
                    printjson(bone);
                }
            }
        );
    }});

Here’s the culprit, notice the null embedded spline.

{
    "_id" : ObjectId("507ea06bd646a40002000759"),
    "splines" : [
        {
            "_id" : ObjectId("508a6911c6e210000200078c"),
                        ....
        },
        null
    ],

You can get rid of it in different ways on the mongo console. In this case we have two splines, one to keep and another to erase.

    var bone = db.bones.findOne({ _id: ObjectId("507ea06bd646a40002000759") })
    bone.splines = [ bone.splines[0] ];
    db.bones.save(a);

How did we get into having this null record anyway? See https://jira.mongodb.org/browse/SERVER-831 and https://github.com/mongoid/mongoid/issues/2545.




Published at DZone with permission of its author, Daniel Doubrovkine. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)