3
3
4
4
from django .db import NotSupportedError
5
5
from django .db .models import (
6
- BooleanField ,
7
- CharField ,
8
- DateField ,
9
- DateTimeField ,
10
6
DecimalField ,
11
7
FloatField ,
12
8
Index ,
13
- IntegerField ,
14
- TextField ,
15
- UUIDField ,
16
9
)
17
10
from django .db .models .lookups import BuiltinLookup
18
11
from django .db .models .sql .query import Query
19
12
from django .db .models .sql .where import AND , XOR , WhereNode
20
13
from pymongo import ASCENDING , DESCENDING
21
14
from pymongo .operations import IndexModel , SearchIndexModel
22
15
23
- from django_mongodb_backend .fields import ArrayField , ObjectIdAutoField , ObjectIdField
16
+ from django_mongodb_backend .fields import ArrayField
24
17
25
18
from .query_utils import process_rhs
26
19
@@ -76,7 +69,7 @@ def where_node_idx(self, compiler, connection):
76
69
return mql
77
70
78
71
79
- def create_mongodb_index (
72
+ def get_pymongo_index_model (
80
73
self ,
81
74
model ,
82
75
schema_editor ,
@@ -124,57 +117,41 @@ def create_mongodb_index(
124
117
125
118
class SearchIndex (Index ):
126
119
suffix = "search"
127
- # Maps Django internal type to atlas search index type.
128
- search_index_data_types = {
129
- "AutoField" : "number" ,
130
- "BigAutoField" : "number" ,
131
- "BinaryField" : "string" ,
132
- "BooleanField" : "boolean" ,
133
- "CharField" : "string" ,
134
- "DateField" : "date" ,
135
- "DateTimeField" : "date" ,
136
- "DecimalField" : "number" ,
137
- "DurationField" : "number" ,
138
- "FileField" : "string" ,
139
- "FilePathField" : "string" ,
140
- "FloatField" : "double" ,
141
- "IntegerField" : "number" ,
142
- "BigIntegerField" : "number" ,
143
- "GenericIPAddressField" : "string" ,
144
- "JSONField" : "document" ,
145
- "OneToOneField" : "number" ,
146
- "PositiveBigIntegerField" : "number" ,
147
- "PositiveIntegerField" : "number" ,
148
- "PositiveSmallIntegerField" : "number" ,
149
- "SlugField" : "string" ,
150
- "SmallAutoField" : "number" ,
151
- "SmallIntegerField" : "number" ,
152
- "TextField" : "string" ,
153
- "TimeField" : "date" ,
154
- "UUIDField" : "uuid" ,
155
- "ObjectIdAutoField" : "objectId" ,
156
- "ObjectIdField" : "objectId" ,
157
- "EmbeddedModelField" : "embeddedDocuments" ,
158
- }
159
-
160
- def __init__ (self , * expressions , ** kwargs ):
161
- super ().__init__ (* expressions , ** kwargs )
162
120
163
- def create_mongodb_index (
121
+ # Maps Django internal type to atlas search index type.
122
+ # Reference: https://www.mongodb.com/docs/atlas/atlas-search/define-field-mappings/#data-types
123
+ def search_index_data_types (self , field , db_type ):
124
+ if field .get_internal_type () == "UUIDField" :
125
+ return "uuid"
126
+ if field .get_internal_type () in ("ObjectIdAutoField" , "ObjectIdField" ):
127
+ return "ObjectId"
128
+ if field .get_internal_type () == "EmbeddedModelField" :
129
+ return "embeddedDocuments"
130
+ if db_type in ("int" , "long" ):
131
+ return "number"
132
+ if db_type == "binData" :
133
+ return "string"
134
+ if db_type == "bool" :
135
+ return "boolean"
136
+ if db_type == "object" :
137
+ return "document"
138
+ return db_type
139
+
140
+ def get_pymongo_index_model (
164
141
self , model , schema_editor , field = None , unique = False , column_prefix = ""
165
142
):
166
143
fields = {}
167
144
for field_name , _ in self .fields_orders :
168
145
field_ = model ._meta .get_field (field_name )
169
- type_ = self .search_index_data_types [ field_ . get_internal_type ()]
146
+ type_ = self .search_index_data_types ( field_ , field_ . db_type ( schema_editor . connection ))
170
147
field_path = column_prefix + model ._meta .get_field (field_name ).column
171
148
fields [field_path ] = {"type" : type_ }
172
149
return SearchIndexModel (
173
150
definition = {"mappings" : {"dynamic" : False , "fields" : fields }}, name = self .name
174
151
)
175
152
176
153
177
- class VectorSearchIndex (Index ):
154
+ class VectorSearchIndex (SearchIndex ):
178
155
suffix = "vector_search"
179
156
ALLOWED_SIMILARITY_FUNCTIONS = frozenset (("euclidean" , "cosine" , "dotProduct" ))
180
157
@@ -195,7 +172,7 @@ def _check_similarity_functions(self, similarities):
195
172
f"'are { ',' .join (self .ALLOWED_SIMILARITY_FUNCTIONS )} "
196
173
)
197
174
198
- def create_mongodb_index (
175
+ def get_pymongo_index_model (
199
176
self , model , schema_editor , field = None , unique = False , column_prefix = ""
200
177
):
201
178
similarities = (
@@ -222,28 +199,23 @@ def create_mongodb_index(
222
199
"similarity" : next (similarities ),
223
200
}
224
201
)
225
- elif isinstance (
226
- field_ ,
227
- BooleanField
228
- | IntegerField
229
- | DateField
230
- | DateTimeField
231
- | CharField
232
- | TextField
233
- | UUIDField
234
- | ObjectIdField
235
- | ObjectIdAutoField ,
236
- ):
237
- mappings ["type" ] = "filter"
238
202
else :
239
- field_type = field_ .get_internal_type ()
240
- raise ValueError (f"Unsupported filter of type { field_type } ." )
203
+ field_type = field_ .db_type (schema_editor .connection )
204
+ search_type = self .search_index_data_types (field_ , field_type )
205
+ # filter - for fields that contain boolean, date, objectId, numeric,
206
+ # string, or UUID values. Reference:
207
+ # https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-type/#atlas-vector-search-index-fields
208
+ if search_type in ("number" , "string" , "boolean" , "objectId" , "uuid" , "date" ):
209
+ mappings ["type" ] = "filter"
210
+ else :
211
+ field_type = field_ .get_internal_type ()
212
+ raise ValueError (f"Unsupported filter of type { field_type } ." )
241
213
fields .append (mappings )
242
214
return SearchIndexModel (definition = {"fields" : fields }, name = self .name , type = "vectorSearch" )
243
215
244
216
245
217
def register_indexes ():
246
218
BuiltinLookup .as_mql_idx = builtin_lookup_idx
247
219
Index ._get_condition_mql = _get_condition_mql
248
- Index .create_mongodb_index = create_mongodb_index
220
+ Index .get_pymongo_index_model = get_pymongo_index_model
249
221
WhereNode .as_mql_idx = where_node_idx
0 commit comments