Skip to content

Commit b65fdf3

Browse files
committed
PYTHON-2142 Add index hinting support to delete operations
1 parent 016f8de commit b65fdf3

29 files changed

+3425
-43
lines changed

pymongo/bulk.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,17 @@ def add_replace(self, selector, replacement, upsert=False,
218218
cmd['hint'] = hint
219219
self.ops.append((_UPDATE, cmd))
220220

221-
def add_delete(self, selector, limit, collation=None):
221+
def add_delete(self, selector, limit, collation=None, hint=None):
222222
"""Create a delete document and add it to the list of ops.
223223
"""
224224
cmd = SON([('q', selector), ('limit', limit)])
225225
collation = validate_collation_or_none(collation)
226226
if collation is not None:
227227
self.uses_collation = True
228228
cmd['collation'] = collation
229+
if hint is not None:
230+
self.uses_hint = True
231+
cmd['hint'] = hint
229232
if limit == _DELETE_ALL:
230233
# A bulk_write containing a delete_many is not retryable.
231234
self.is_retryable = False

pymongo/collection.py

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ def drop(self, session=None):
11251125
def _delete(
11261126
self, sock_info, criteria, multi,
11271127
write_concern=None, op_id=None, ordered=True,
1128-
collation=None, session=None, retryable_write=False):
1128+
collation=None, hint=None, session=None, retryable_write=False):
11291129
"""Internal delete helper."""
11301130
common.validate_is_mapping("filter", criteria)
11311131
write_concern = write_concern or self.write_concern
@@ -1142,6 +1142,16 @@ def _delete(
11421142
'Collation is unsupported for unacknowledged writes.')
11431143
else:
11441144
delete_doc['collation'] = collation
1145+
if hint is not None:
1146+
if sock_info.max_wire_version < 5:
1147+
raise ConfigurationError(
1148+
'Must be connected to MongoDB 3.4+ to use hint.')
1149+
elif not acknowledged:
1150+
raise ConfigurationError(
1151+
'hint is unsupported for unacknowledged writes.')
1152+
if not isinstance(hint, string_type):
1153+
hint = helpers._index_document(hint)
1154+
delete_doc['hint'] = hint
11451155
command = SON([('delete', self.name),
11461156
('ordered', ordered),
11471157
('deletes', [delete_doc])])
@@ -1171,20 +1181,20 @@ def _delete(
11711181
def _delete_retryable(
11721182
self, criteria, multi,
11731183
write_concern=None, op_id=None, ordered=True,
1174-
collation=None, session=None):
1184+
collation=None, hint=None, session=None):
11751185
"""Internal delete helper."""
11761186
def _delete(session, sock_info, retryable_write):
11771187
return self._delete(
11781188
sock_info, criteria, multi,
11791189
write_concern=write_concern, op_id=op_id, ordered=ordered,
1180-
collation=collation, session=session,
1190+
collation=collation, hint=hint, session=session,
11811191
retryable_write=retryable_write)
11821192

11831193
return self.__database.client._retryable_write(
11841194
(write_concern or self.write_concern).acknowledged and not multi,
11851195
_delete, session)
11861196

1187-
def delete_one(self, filter, collation=None, session=None):
1197+
def delete_one(self, filter, collation=None, hint=None, session=None):
11881198
"""Delete a single document matching the filter.
11891199
11901200
>>> db.test.count_documents({'x': 1})
@@ -1200,29 +1210,35 @@ def delete_one(self, filter, collation=None, session=None):
12001210
- `collation` (optional): An instance of
12011211
:class:`~pymongo.collation.Collation`. This option is only supported
12021212
on MongoDB 3.4 and above.
1213+
- `hint` (optional): An index to use to support the query
1214+
predicate specified either by its string name, or in the same
1215+
format as passed to
1216+
:meth:`~pymongo.collection.Collection.create_index` (e.g.
1217+
``[('field', ASCENDING)]``). This option is only supported on
1218+
MongoDB 4.4 and above.
12031219
- `session` (optional): a
12041220
:class:`~pymongo.client_session.ClientSession`.
12051221
12061222
:Returns:
12071223
- An instance of :class:`~pymongo.results.DeleteResult`.
12081224
1225+
.. versionchanged:: 3.11
1226+
Added ``hint`` parameter.
12091227
.. versionchanged:: 3.6
12101228
Added ``session`` parameter.
1211-
12121229
.. versionchanged:: 3.4
12131230
Added the `collation` option.
1214-
12151231
.. versionadded:: 3.0
12161232
"""
12171233
write_concern = self._write_concern_for(session)
12181234
return DeleteResult(
12191235
self._delete_retryable(
12201236
filter, False,
12211237
write_concern=write_concern,
1222-
collation=collation, session=session),
1238+
collation=collation, hint=hint, session=session),
12231239
write_concern.acknowledged)
12241240

1225-
def delete_many(self, filter, collation=None, session=None):
1241+
def delete_many(self, filter, collation=None, hint=None, session=None):
12261242
"""Delete one or more documents matching the filter.
12271243
12281244
>>> db.test.count_documents({'x': 1})
@@ -1238,26 +1254,32 @@ def delete_many(self, filter, collation=None, session=None):
12381254
- `collation` (optional): An instance of
12391255
:class:`~pymongo.collation.Collation`. This option is only supported
12401256
on MongoDB 3.4 and above.
1257+
- `hint` (optional): An index to use to support the query
1258+
predicate specified either by its string name, or in the same
1259+
format as passed to
1260+
:meth:`~pymongo.collection.Collection.create_index` (e.g.
1261+
``[('field', ASCENDING)]``). This option is only supported on
1262+
MongoDB 4.4 and above.
12411263
- `session` (optional): a
12421264
:class:`~pymongo.client_session.ClientSession`.
12431265
12441266
:Returns:
12451267
- An instance of :class:`~pymongo.results.DeleteResult`.
12461268
1269+
.. versionchanged:: 3.11
1270+
Added ``hint`` parameter.
12471271
.. versionchanged:: 3.6
12481272
Added ``session`` parameter.
1249-
12501273
.. versionchanged:: 3.4
12511274
Added the `collation` option.
1252-
12531275
.. versionadded:: 3.0
12541276
"""
12551277
write_concern = self._write_concern_for(session)
12561278
return DeleteResult(
12571279
self._delete_retryable(
12581280
filter, True,
12591281
write_concern=write_concern,
1260-
collation=collation, session=session),
1282+
collation=collation, hint=hint, session=session),
12611283
write_concern.acknowledged)
12621284

12631285
def find_one(self, filter=None, *args, **kwargs):
@@ -2849,10 +2871,8 @@ def inline_map_reduce(self, map, reduce, full_response=False, session=None,
28492871
28502872
.. versionchanged:: 3.6
28512873
Added ``session`` parameter.
2852-
28532874
.. versionchanged:: 3.4
28542875
Added the `collation` option.
2855-
28562876
"""
28572877
res = self._map_reduce(map, reduce, {"inline": 1}, session,
28582878
self.read_preference, **kwargs)
@@ -2931,7 +2951,8 @@ def _find_and_modify(session, sock_info, retryable_write):
29312951
write_concern.acknowledged, _find_and_modify, session)
29322952

29332953
def find_one_and_delete(self, filter,
2934-
projection=None, sort=None, session=None, **kwargs):
2954+
projection=None, sort=None, hint=None,
2955+
session=None, **kwargs):
29352956
"""Finds a single document and deletes it, returning the document.
29362957
29372958
>>> db.test.count_documents({'x': 1})
@@ -2968,15 +2989,21 @@ def find_one_and_delete(self, filter,
29682989
- `sort` (optional): a list of (key, direction) pairs
29692990
specifying the sort order for the query. If multiple documents
29702991
match the query, they are sorted and the first is deleted.
2992+
- `hint` (optional): An index to use to support the query predicate
2993+
specified either by its string name, or in the same format as
2994+
passed to :meth:`~pymongo.collection.Collection.create_index`
2995+
(e.g. ``[('field', ASCENDING)]``). This option is only supported
2996+
on MongoDB 4.4 and above.
29712997
- `session` (optional): a
29722998
:class:`~pymongo.client_session.ClientSession`.
29732999
- `**kwargs` (optional): additional command arguments can be passed
29743000
as keyword arguments (for example maxTimeMS can be used with
29753001
recent server versions).
29763002
3003+
.. versionchanged:: 3.11
3004+
Added ``hint`` parameter.
29773005
.. versionchanged:: 3.6
29783006
Added ``session`` parameter.
2979-
29803007
.. versionchanged:: 3.2
29813008
Respects write concern.
29823009
@@ -2989,11 +3016,10 @@ def find_one_and_delete(self, filter,
29893016
.. versionchanged:: 3.4
29903017
Added the `collation` option.
29913018
.. versionadded:: 3.0
2992-
29933019
"""
29943020
kwargs['remove'] = True
29953021
return self.__find_and_modify(filter, projection, sort,
2996-
session=session, **kwargs)
3022+
hint=hint, session=session, **kwargs)
29973023

29983024
def find_one_and_replace(self, filter, replacement,
29993025
projection=None, sort=None, upsert=False,

pymongo/operations.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ def __ne__(self, other):
5757
class DeleteOne(object):
5858
"""Represents a delete_one operation."""
5959

60-
__slots__ = ("_filter", "_collation")
60+
__slots__ = ("_filter", "_collation", "_hint")
6161

62-
def __init__(self, filter, collation=None):
62+
def __init__(self, filter, collation=None, hint=None):
6363
"""Create a DeleteOne instance.
6464
6565
For use with :meth:`~pymongo.collection.Collection.bulk_write`.
@@ -69,18 +69,31 @@ def __init__(self, filter, collation=None):
6969
- `collation` (optional): An instance of
7070
:class:`~pymongo.collation.Collation`. This option is only
7171
supported on MongoDB 3.4 and above.
72+
- `hint` (optional): An index to use to support the query
73+
predicate specified either by its string name, or in the same
74+
format as passed to
75+
:meth:`~pymongo.collection.Collection.create_index` (e.g.
76+
``[('field', ASCENDING)]``). This option is only supported on
77+
MongoDB 4.4 and above.
7278
79+
.. versionchanged:: 3.11
80+
Added the ``hint`` option.
7381
.. versionchanged:: 3.5
7482
Added the `collation` option.
7583
"""
7684
if filter is not None:
7785
validate_is_mapping("filter", filter)
86+
if hint is not None:
87+
if not isinstance(hint, string_type):
88+
hint = helpers._index_document(hint)
7889
self._filter = filter
7990
self._collation = collation
91+
self._hint = hint
8092

8193
def _add_to_bulk(self, bulkobj):
8294
"""Add this operation to the _Bulk instance `bulkobj`."""
83-
bulkobj.add_delete(self._filter, 1, collation=self._collation)
95+
bulkobj.add_delete(self._filter, 1, collation=self._collation,
96+
hint=self._hint)
8497

8598
def __repr__(self):
8699
return "DeleteOne(%r, %r)" % (self._filter, self._collation)
@@ -98,9 +111,9 @@ def __ne__(self, other):
98111
class DeleteMany(object):
99112
"""Represents a delete_many operation."""
100113

101-
__slots__ = ("_filter", "_collation")
114+
__slots__ = ("_filter", "_collation", "_hint")
102115

103-
def __init__(self, filter, collation=None):
116+
def __init__(self, filter, collation=None, hint=None):
104117
"""Create a DeleteMany instance.
105118
106119
For use with :meth:`~pymongo.collection.Collection.bulk_write`.
@@ -110,18 +123,31 @@ def __init__(self, filter, collation=None):
110123
- `collation` (optional): An instance of
111124
:class:`~pymongo.collation.Collation`. This option is only
112125
supported on MongoDB 3.4 and above.
126+
- `hint` (optional): An index to use to support the query
127+
predicate specified either by its string name, or in the same
128+
format as passed to
129+
:meth:`~pymongo.collection.Collection.create_index` (e.g.
130+
``[('field', ASCENDING)]``). This option is only supported on
131+
MongoDB 4.4 and above.
113132
133+
.. versionchanged:: 3.11
134+
Added the ``hint`` option.
114135
.. versionchanged:: 3.5
115136
Added the `collation` option.
116137
"""
117138
if filter is not None:
118139
validate_is_mapping("filter", filter)
140+
if hint is not None:
141+
if not isinstance(hint, string_type):
142+
hint = helpers._index_document(hint)
119143
self._filter = filter
120144
self._collation = collation
145+
self._hint = hint
121146

122147
def _add_to_bulk(self, bulkobj):
123148
"""Add this operation to the _Bulk instance `bulkobj`."""
124-
bulkobj.add_delete(self._filter, 0, collation=self._collation)
149+
bulkobj.add_delete(self._filter, 0, collation=self._collation,
150+
hint=self._hint)
125151

126152
def __repr__(self):
127153
return "DeleteMany(%r, %r)" % (self._filter, self._collation)

test/crud/v2/aggregate-merge.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"runOn": [
33
{
4-
"minServerVersion": "4.2.0"
4+
"minServerVersion": "4.1.11"
55
}
66
],
77
"data": [

0 commit comments

Comments
 (0)