Skip to content

Commit 14ce3af

Browse files
committed
PYTHON-861 - Implement list_indexes.
1 parent 9c4d017 commit 14ce3af

5 files changed

Lines changed: 69 additions & 27 deletions

File tree

doc/api/pymongo/collection.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
.. automethod:: drop_index
5757
.. automethod:: drop_indexes
5858
.. automethod:: reindex
59+
.. automethod:: list_indexes
5960
.. automethod:: index_information
6061
.. automethod:: drop
6162
.. automethod:: rename

doc/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ The following methods have been added:
268268
- :meth:`~pymongo.collection.Collection.find_one_and_update`
269269
- :meth:`~pymongo.collection.Collection.with_options`
270270
- :meth:`~pymongo.collection.Collection.create_indexes`
271+
- :meth:`~pymongo.collection.Collection.list_indexes`
271272

272273
The following methods have changed:
273274

pymongo/collection.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,27 @@ def reindex(self):
11931193
cmd = SON([("reIndex", self.__name)])
11941194
return self._command(cmd, ReadPreference.PRIMARY)[0]
11951195

1196+
def list_indexes(self):
1197+
"""Get a cursor over the indexes for this collection."""
1198+
client = self.__database.client
1199+
if client._writable_max_wire_version() > 2:
1200+
cmd = SON([("listIndexes", self.__name), ("cursor", {})])
1201+
res, addr = self._command(cmd,
1202+
ReadPreference.PRIMARY,
1203+
CodecOptions(SON))
1204+
cursor = res["cursor"]
1205+
else:
1206+
namespace = "%s.%s" % (self.__database.name, "system.indexes")
1207+
res, addr = helpers._first_batch(
1208+
client, namespace, {"ns": self.__full_name},
1209+
0, ReadPreference.PRIMARY, CodecOptions(SON))
1210+
cursor = {
1211+
"id": res["cursor_id"],
1212+
"firstBatch": res["data"],
1213+
"ns": namespace,
1214+
}
1215+
return CommandCursor(self, cursor, addr)
1216+
11961217
def index_information(self):
11971218
"""Get information on this collection's indexes.
11981219
@@ -1212,26 +1233,9 @@ def index_information(self):
12121233
{u'_id_': {u'key': [(u'_id', 1)]},
12131234
u'x_1': {u'unique': True, u'key': [(u'x', 1)]}}
12141235
"""
1215-
client = self.__database.client
1216-
if client._writable_max_wire_version() > 2:
1217-
cmd = SON([("listIndexes", self.__name), ("cursor", {})])
1218-
res, addr = self._command(cmd,
1219-
ReadPreference.PRIMARY,
1220-
CodecOptions(document_class=SON))
1221-
# MongoDB 2.8rc2
1222-
if "indexes" in res:
1223-
raw = res["indexes"]
1224-
# >= MongoDB 2.8rc3
1225-
else:
1226-
raw = CommandCursor(self, res["cursor"], addr)
1227-
else:
1228-
raw = self.__database.get_collection(
1229-
"system.indexes",
1230-
codec_options=CodecOptions(document_class=SON),
1231-
read_preference=ReadPreference.PRIMARY).find(
1232-
{"ns": self.__full_name}, {"ns": 0})
1236+
cursor = self.list_indexes()
12331237
info = {}
1234-
for index in raw:
1238+
for index in cursor:
12351239
index["key"] = index["key"].items()
12361240
index = dict(index)
12371241
info[index.pop("name")] = index

pymongo/helpers.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,29 +184,38 @@ def _check_command_response(response, msg=None, allowable_errors=None):
184184
raise OperationFailure(msg % errmsg, code, response)
185185

186186

187-
def _command(client, namespace, command, read_preference,
188-
codec_options, check=True, allowable_errors=None):
189-
"""Internal command helper."""
190-
187+
def _first_batch(client, namespace, query,
188+
limit, read_preference, codec_options):
189+
"""Simple query helper for retrieving a first (and possibly only) batch."""
191190
query_opts = 0
192191
# XXX: Set slaveOkay flag when read preference mode is anything other
193192
# than primary (0). Make this more clear when we finish refactoring
194193
# read preferences.
195194
if read_preference.mode:
196195
query_opts = 4
197196

198-
query = _Query(query_opts, namespace, 0, -1, command, None, codec_options)
197+
query = _Query(
198+
query_opts, namespace, 0, limit, query, None, codec_options)
199199
response = client._send_message_with_response(query, read_preference)
200-
result = _unpack_response(response.data, None, codec_options)['data'][0]
200+
return _unpack_response(
201+
response.data, None, codec_options), response.address
202+
203+
204+
def _command(client, namespace, command, read_preference,
205+
codec_options, check=True, allowable_errors=None):
206+
"""Internal command helper."""
207+
result, addr = _first_batch(
208+
client, namespace, command, -1, read_preference, codec_options)
209+
result = result["data"][0]
201210
if check:
202211
msg = "command %s on namespace %s failed: %%s" % (
203212
repr(command).replace("%", "%%"), namespace)
204213
try:
205214
_check_command_response(result, msg, allowable_errors)
206215
except NotMasterError:
207-
client._reset_server_and_request_check(response.address)
216+
client._reset_server_and_request_check(addr)
208217
raise
209-
return result, response.address
218+
return result, addr
210219

211220

212221
def _check_write_command_response(results):

test/test_collection.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,33 @@ def check_result(result):
260260
else:
261261
check_result(reindexed)
262262

263+
def test_list_indexes(self):
264+
db = self.db
265+
db.test.drop()
266+
db.test.insert_one({}) # create collection
267+
268+
def map_indexes(indexes):
269+
return dict([(index["name"], index) for index in indexes])
270+
271+
indexes = list(db.test.list_indexes())
272+
self.assertEqual(len(indexes), 1)
273+
self.assertTrue("_id_" in map_indexes(indexes))
274+
275+
db.test.create_index("hello")
276+
indexes = list(db.test.list_indexes())
277+
self.assertEqual(len(indexes), 2)
278+
self.assertEqual(map_indexes(indexes)["hello_1"]["key"],
279+
SON([("hello", ASCENDING)]))
280+
281+
db.test.create_index([("hello", DESCENDING), ("world", ASCENDING)],
282+
unique=True)
283+
indexes = list(db.test.list_indexes())
284+
self.assertEqual(len(indexes), 3)
285+
index_map = map_indexes(indexes)
286+
self.assertEqual(index_map["hello_-1_world_1"]["key"],
287+
SON([("hello", DESCENDING), ("world", ASCENDING)]))
288+
self.assertEqual(True, index_map["hello_-1_world_1"]["unique"])
289+
263290
def test_index_info(self):
264291
db = self.db
265292
db.test.drop()

0 commit comments

Comments
 (0)