2011-08-06

How to Fix Erroneously Named MongoDB Collections

In MongoDB, collections are not supposed to include certain characters like, for example, a hyphen "-" or a slash "/". The manual has this to say on the matter:
Collection names should begin with letters or an underscore and may include numbers; $ is reserved. Collections can be organized in namespaces; these are named groups of collections defined using a dot notation.
The keyword here is "should".
It is possible to create collations with names that do not adhere to these rules. This is not enforced at all. When you try to access such a collection from the shell, things don't quite work as expected:
>db.test-col.find()
Sat Aug  6 14:54:06 ReferenceError: col is not defined (shell):1
This is because the javascript console tries to subtract "col" from "test". I've tried different escaping methods for the rogue hyphen, but couldn't find one that works.
Eventually, I've reverted to using the more "internal" renameCollection command, to rename the collection into something manageable:
>db.runCommand({renameCollection:"test.test-col",to:"test.test_col"})
Which solves the problem completely.

Now you might be wondering: how was this created in the first place? Because if you can't read from this collection, you can't "save" into it from the shell as well.
We have a nice list of commands here which I recommend to anyone who's working with MongoDB to be familiar with. One of these commands is the aptly named "create", which will obediently create a collection with such a name:
>db.runCommand({"create":"test-col"});
{ "ok" : 1 }
I can only assume drivers use this same command to create the collections, which was how it was created in the first place.

5 comments:

  1. Thanks! Decided to avoid the hyphen in a new collection altogether after reading your post.

    ReplyDelete
  2. Hi,

    I got:
    { "errmsg" : "access denied; use admin db", "ok" : 0 }

    so I needed to change to the admin db:
    < use admin
    switched to db admin


    Only then did I get:
    { "ok" : 1 }

    ReplyDelete
  3. For reference to everyone who found this through google simply use Square Bracket notation:

    db["test-col"].drop();

    ReplyDelete
    Replies
    1. Thanks man! The command was not working fore me, since it could be run only on admin db and I had data in a different db. so you can use db["badNameCollection"].copyTo("someThingBetter")

      Delete
  4. FYI, there's a much easier syntax for accessing these, at least in many mongo versions (I don't know how old it is)

    db["test-col"].find()

    ReplyDelete