With PyMongo how do I import indexes using create_index() that were exported with index_information()?

1,027 views
Skip to first unread message

Robert Parker

unread,
Jul 8, 2015, 1:46:57 PM7/8/15
to mongod...@googlegroups.com
What do you need to do to the output of index_information() such that it can then be re-imported using create_index() or create_indexes() ?

>>> from pymongo import MongoClient
>>> client = MongoClient("mongodb://host1")
>>> db = client.MYDB
>>> collection = db.MYCOLLECTION
>>> index = db.provisioning.index_information()
>>> index
{u'_id_': {u'ns': u'MYDB.MYCOLLECTION', u'key': [(u'_id', 1)], u'v': 1}, u'Name_1': {u'unique': True, u'key': [(u'Name', 1)], u'v': 1, u'ns': u'MYDB.MYCOLLECTION', u'background': False}, u'MongoType_1': {u'key': [(u'MongoType', 1)], u'ns': u'MYDB.MYCOLLECTION', u'background': False, u'v': 1}}
>>> client2 = MongoClient("mongodb://host2")
>>> db2 = client2.MYDB
>>> collection2 = db2.MYCOLLECTION
>>> collection2.create_index(index)
Traceback (most recent call last):
 
File "<stdin>", line 1, in <module>
 
File "/usr/lib64/python2.6/site-packages/pymongo/collection.py", line 1161, in create_index
    keys
= helpers._index_list(keys)
 
File "/usr/lib64/python2.6/site-packages/pymongo/helpers.py", line 55, in _index_list
   
raise TypeError("if no direction is specified, "
TypeError: if no direction is specified, key_or_list must be an instance of list
>>> collection2.create_indexes(index)
Traceback (most recent call last):
 
File "<stdin>", line 1, in <module>
 
File "/usr/lib64/python2.6/site-packages/pymongo/collection.py", line 1046, in create_indexes
   
raise TypeError("indexes must be a list")
TypeError: indexes must be a list

How would I iterate over the lists of indexes output by index_information(), such that create_index() or create_indexes() can import them?

>>> for item in index.iteritems():
...     collection2.create_index(item)
...
Traceback (most recent call last):
 
File "<stdin>", line 2, in <module>
 
File "/usr/lib64/python2.6/site-packages/pymongo/collection.py", line 1162, in create_index
    name
= kwargs.setdefault("name", helpers._gen_index_name(keys))
 
File "/usr/lib64/python2.6/site-packages/pymongo/helpers.py", line 41, in _gen_index_name
   
return _UUNDER.join(["%s_%s" % item for item in keys])
TypeError: not enough arguments for format string

Thanks in advance

Bernie Hackett

unread,
Jul 9, 2015, 1:26:52 PM7/9/15
to mongod...@googlegroups.com, repar...@gmail.com
Don't use index_information(). Use list_indexes() instead. That returns an iterable of the index documents from the server.  You will have to remove the 'ns' field from each index document. You will also want to skip the _id index (name '_id_'). It will likely be easier for you to just call the createIndexes command directly using Database.command.

Robert Parker

unread,
Jul 9, 2015, 2:06:13 PM7/9/15
to mongod...@googlegroups.com, repar...@gmail.com
Can you show me an example?  My goal is to be able to export indexes from once instance's collections to a JSON and then later read that JSON and re-import the indexes to another instance.  Mongoexport/mongoimport won't help with this since I just want the indexes, not the data and you can't get access to system.indexes collection anymore in MongoDB 3.0.

Bernie Hackett

unread,
Jul 9, 2015, 7:35:09 PM7/9/15
to mongod...@googlegroups.com
Here's an example:

>>> client.indextest.source.create_index([('a', -1)], background=True)
u'a_-1'
>>> list(client.indextest.source.list_indexes())
[SON([(u'v', 1), (u'key', SON([(u'_id', 1)])), (u'name', u'_id_'), (u'ns', u'indextest.source')]), SON([(u'v', 1), (u'key', SON([(u'a', -1)])), (u'name', u'a_-1'), (u'ns', u'indextest.source'), (u'background', True)])]
>>> def clean_indexes(indexes):
...          for index in indexes:
...              if index['name'] == '_id_':
...                  continue
...              index.pop('ns', None)
...              yield index
... 
>>> c.indextest.command('createIndexes', 'destination', indexes=[index for index in clean_indexes(c.indextest.source.list_indexes())])
{u'createdCollectionAutomatically': True, u'numIndexesAfter': 2, u'ok': 1.0, u'numIndexesBefore': 1}
>>> list(c.indextest.destination.list_indexes())
[SON([(u'v', 1), (u'key', SON([(u'_id', 1)])), (u'name', u'_id_'), (u'ns', u'indextest.destination')]), SON([(u'v', 1), (u'key', SON([(u'a', -1)])), (u'name', u'a_-1'), (u'ns', u'indextest.destination'), (u'background', True)])]

If you're going to store the indexes as JSON documents to restore later using python you *must* make sure the documents are JSON decoded to OrderedDict. This is necessary to preserve the order of the index keys. There is an example here:

Robert Parker

unread,
Jul 10, 2015, 10:25:44 AM7/10/15
to mongod...@googlegroups.com
That seems awful complicated for the task at hand.  What then is the preferred method of indirectly exporting and importing indexes between instances of mongodb when you ONLY want to preserve indexes, not the actual data in the collection, especially now that mongodb 3.0 has the system.indexes collection deprecated? 

Bernie Hackett

unread,
Jul 13, 2015, 9:59:34 PM7/13/15
to mongod...@googlegroups.com, repar...@gmail.com
It's not as nice as using mongoexport against system.indexes, that's for sure. I've opened a ticket in the tools project to request the feature it sounds like you really want.

Reply all
Reply to author
Forward
0 new messages