@@ -87,62 +87,40 @@ public function updateDocumentIndexes($documentName)
87
87
88
88
if ($ documentIndexes = $ this ->getDocumentIndexes ($ documentName )) {
89
89
90
- $ defaults = array (
91
- 'safe ' => true ,
92
- 'dropDups ' => false ,
93
- 'background ' => false ,
94
- 'unique ' => false ,
95
- 'sparse ' => false ,
96
- );
97
- foreach ($ documentIndexes as &$ documentIndex ) {
98
- $ documentIndex ['options ' ] = array_merge ($ defaults , $ documentIndex ['options ' ]);
99
- }
100
-
101
- if ($ collection = $ this ->dm ->getDocumentCollection ($ class ->name )) {
102
-
103
- $ mongoIndexes = $ collection ->getIndexInfo ();
104
- foreach ($ mongoIndexes as $ i => $ mongoIndex ) {
105
- if ($ mongoIndex ['name ' ] === '_id_ ' ) {
106
- unset($ mongoIndexes [$ i ]);
107
- continue ;
108
- }
109
- $ mongoIndexes [$ i ] = $ this ->rawIndexToDocumentIndex ($ mongoIndex );
90
+ $ collection = $ this ->dm ->getDocumentCollection ($ documentName );
91
+ $ mongoIndexes = $ collection ->getIndexInfo ();
92
+
93
+ /* Determine which Mongo indexes should be deleted. Exclude the ID
94
+ * index and those that are equivalent to any in the class metadata.
95
+ */
96
+ $ mongoIndexes = array_filter ($ mongoIndexes , function ($ mongoIndex ) use ($ documentIndexes ) {
97
+ if ('_id_ ' === $ mongoIndex ['name ' ]) {
98
+ return false ;
110
99
}
111
100
112
- $ update = false ;
113
- foreach ($ documentIndexes as $ i => $ documentIndex ) {
114
- // Remove each index from array that exists already
115
- foreach ($ mongoIndexes as $ j => $ mongoIndex ) {
116
- $ keyDiff = array_diff_assoc ($ mongoIndex ['keys ' ], $ documentIndex ['keys ' ]);
117
- $ optDiff = array_diff_assoc ($ mongoIndex ['options ' ], $ documentIndex ['options ' ]);
118
- if (empty ($ keyDiff )) {
119
- if (empty ($ optDiff ) || (count ($ optDiff ) === 1 && isset ($ optDiff ['name ' ]))) {
120
- // Index exists exactly as document
121
- unset($ mongoIndexes [$ j ]);
122
- continue ;
123
- } else {
124
- // Only options differ, update
125
- unset($ mongoIndexes [$ j ]);
126
- $ update = true ;
127
- }
128
- }
129
- }
130
- }
131
-
132
- // The rest need to be deleted
133
- foreach ($ mongoIndexes as $ mongoIndex ) {
134
- if (isset ($ mongoIndex ['options ' ]['name ' ])) {
135
- $ collection ->getDatabase ()->command (array (
136
- 'deleteIndexes ' => $ collection ->getName (),
137
- 'index ' => $ mongoIndex ['options ' ]['name ' ]
138
- ));
101
+ foreach ($ documentIndexes as $ documentIndex ) {
102
+ if ($ this ->isMongoIndexEquivalentToDocumentIndex ($ mongoIndex , $ documentIndex )) {
103
+ return false ;
139
104
}
140
105
}
141
106
142
- if ($ update ) {
143
- $ this ->ensureDocumentIndexes ($ documentName );
107
+ return true ;
108
+ });
109
+
110
+ // Delete indexes that do not exist in class metadata
111
+ foreach ($ mongoIndexes as $ mongoIndex ) {
112
+ if (isset ($ mongoIndex ['name ' ])) {
113
+ /* Note: MongoCollection::deleteIndex() cannot delete
114
+ * custom-named indexes, so use the deleteIndexes command.
115
+ */
116
+ $ collection ->getDatabase ()->command (array (
117
+ 'deleteIndexes ' => $ collection ->getName (),
118
+ 'index ' => $ mongoIndex ['name ' ],
119
+ ));
144
120
}
145
121
}
122
+
123
+ $ this ->ensureDocumentIndexes ($ documentName );
146
124
}
147
125
}
148
126
@@ -179,37 +157,6 @@ public function getAllIndexes($raw = true)
179
157
return $ all ;
180
158
}
181
159
182
- /**
183
- * Returns all document indexes - indexed by documentName
184
- *
185
- * @return array
186
- */
187
- public function getAllDocumentIndexes ()
188
- {
189
- $ return = array ();
190
- $ defaults = array (
191
- 'safe ' => true ,
192
- 'dropDups ' => false ,
193
- 'background ' => false ,
194
- 'unique ' => false ,
195
- 'sparse ' => false ,
196
- );
197
-
198
- foreach ($ this ->metadataFactory ->getAllMetadata () as $ class ) {
199
- if ($ class ->isMappedSuperclass || $ class ->isEmbeddedDocument ) {
200
- continue ;
201
- }
202
- if ($ indexes = $ this ->getDocumentIndexes ($ class ->name )) {
203
- foreach ($ indexes as &$ index ) {
204
- $ index ['options ' ] = array_merge ($ defaults , $ index ['options ' ]);
205
- }
206
- $ return [$ class ->name ] = $ indexes ;
207
- }
208
- }
209
-
210
- return $ return ;
211
- }
212
-
213
160
public function getDocumentIndexes ($ documentName )
214
161
{
215
162
$ visited = array ();
@@ -451,23 +398,56 @@ public function createDocumentDatabase($documentName)
451
398
}
452
399
453
400
/**
454
- * Convert an array from a raw MongoDB index to ODM style.
401
+ * Determine if an index returned by MongoCollection::getIndexInfo() can be
402
+ * considered equivalent to an index in class metadata.
455
403
*
456
- * @param array $rawIndex
457
- * @return array
404
+ * Indexes are considered different if:
405
+ *
406
+ * (a) Key/direction pairs differ or are not in the same order
407
+ * (b) Sparse or unique options differ
408
+ * (c) Mongo index is unique without dropDups and mapped index is unique
409
+ * with dropDups
410
+ * (d) Geospatial options differ (bits, max, min)
411
+ *
412
+ * Regarding (c), the inverse case is not a reason to delete and
413
+ * recreate the index, since dropDups only affects creation of
414
+ * the unique index. Additionally, the background option is only
415
+ * relevant to index creation and is not considered.
458
416
*/
459
- private function rawIndexToDocumentIndex ( $ rawIndex )
417
+ private function isMongoIndexEquivalentToDocumentIndex ( $ mongoIndex , $ documentIndex )
460
418
{
461
- return array (
462
- 'keys ' => $ rawIndex ['key ' ],
463
- 'options ' => array (
464
- 'name ' => $ rawIndex ['name ' ],
465
- 'safe ' => isset ($ rawIndex ['safe ' ]) ? $ rawIndex ['safe ' ] : true ,
466
- 'dropDups ' => isset ($ rawIndex ['dropDups ' ]) ? $ rawIndex ['dropDups ' ] : false ,
467
- 'background ' => isset ($ rawIndex ['background ' ]) ? $ rawIndex ['background ' ] : false ,
468
- 'unique ' => isset ($ rawIndex ['unique ' ]) ? $ rawIndex ['unique ' ] : false ,
469
- 'sparse ' => isset ($ rawIndex ['sparse ' ]) ? $ rawIndex ['sparse ' ] : false ,
470
- )
471
- );
419
+ $ documentIndexOptions = $ documentIndex ['options ' ];
420
+
421
+ if ($ mongoIndex ['key ' ] !== $ documentIndex ['keys ' ]) {
422
+ return false ;
423
+ }
424
+
425
+ if (empty ($ mongoIndex ['sparse ' ]) xor empty ($ documentIndexOptions ['sparse ' ])) {
426
+ return false ;
427
+ }
428
+
429
+ if (empty ($ mongoIndex ['unique ' ]) xor empty ($ documentIndexOptions ['unique ' ])) {
430
+ return false ;
431
+ }
432
+
433
+ if (!empty ($ mongoIndex ['unique ' ]) && empty ($ mongoIndex ['dropDups ' ]) &&
434
+ !empty ($ documentIndexOptions ['unique ' ]) && !empty ($ documentIndexOptions )) {
435
+
436
+ return false ;
437
+ }
438
+
439
+ foreach (array ('bits ' , 'max ' , 'min ' ) as $ option ) {
440
+ if (isset ($ mongoIndex [$ option ]) xor isset ($ documentIndexOptions [$ option ])) {
441
+ return false ;
442
+ }
443
+
444
+ if (isset ($ mongoIndex [$ option ]) && isset ($ documentIndexOptions [$ option ]) &&
445
+ $ mongoIndex [$ option ] !== $ documentIndexOptions [$ option ]) {
446
+
447
+ return false ;
448
+ }
449
+ }
450
+
451
+ return true ;
472
452
}
473
453
}
0 commit comments