/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/WildcardIndex.java

http://github.com/SpringSource/spring-data-mongodb · Java · 198 lines · 73 code · 24 blank · 101 comment · 3 complexity · 9d0fc62cb38b52093b48b1e95b9ab180 MD5 · raw file

  1. /*
  2. * Copyright 2021 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.data.mongodb.core.index;
  17. import java.time.Duration;
  18. import java.util.LinkedHashMap;
  19. import java.util.Map;
  20. import java.util.concurrent.TimeUnit;
  21. import org.bson.Document;
  22. import org.springframework.lang.Nullable;
  23. import org.springframework.util.CollectionUtils;
  24. import org.springframework.util.StringUtils;
  25. /**
  26. * {@link WildcardIndex} is a specific {@link Index} that can be used to include all fields into an index based on the
  27. * {@code $**" : 1} pattern on a root object (the one typically carrying the
  28. * {@link org.springframework.data.mongodb.core.mapping.Document} annotation). On those it is possible to use
  29. * {@link #wildcardProjectionInclude(String...)} and {@link #wildcardProjectionExclude(String...)} to define specific
  30. * paths for in-/exclusion.
  31. * <br />
  32. * It can also be used to define an index on a specific field path and its subfields, e.g.
  33. * {@code "path.to.field.$**" : 1}. <br />
  34. * Note that {@literal wildcardProjections} are not allowed in this case.
  35. * <br />
  36. * <strong>LIMITATIONS</strong><br />
  37. * <ul>
  38. * <li>{@link #unique() Unique} and {@link #expire(long) ttl} options are not supported.</li>
  39. * <li>Keys used for sharding must not be included</li>
  40. * <li>Cannot be used to generate any type of geo index.</li>
  41. * </ul>
  42. *
  43. * @author Christoph Strobl
  44. * @see <a href= "https://docs.mongodb.com/manual/core/index-wildcard/">MongoDB Reference Documentation: Wildcard
  45. * Indexes/</a>
  46. * @since 3.3
  47. */
  48. public class WildcardIndex extends Index {
  49. private @Nullable String fieldName;
  50. private final Map<String, Object> wildcardProjection = new LinkedHashMap<>();
  51. /**
  52. * Create a new instance of {@link WildcardIndex} using {@code $**}.
  53. */
  54. public WildcardIndex() {}
  55. /**
  56. * Create a new instance of {@link WildcardIndex} for the given {@literal path}. If no {@literal path} is provided the
  57. * index will be considered a root one using {@code $**}. <br />
  58. * <strong>NOTE</strong> {@link #wildcardProjectionInclude(String...)}, {@link #wildcardProjectionExclude(String...)}
  59. * can only be used for top level index definitions having an {@literal empty} or {@literal null} path.
  60. *
  61. * @param path can be {@literal null}. If {@literal null} all fields will be indexed.
  62. */
  63. public WildcardIndex(@Nullable String path) {
  64. this.fieldName = path;
  65. }
  66. /**
  67. * Include the {@code _id} field in {@literal wildcardProjection}.
  68. *
  69. * @return this.
  70. */
  71. public WildcardIndex includeId() {
  72. wildcardProjection.put("_id", 1);
  73. return this;
  74. }
  75. /**
  76. * Set the index name to use.
  77. *
  78. * @param name
  79. * @return this.
  80. */
  81. @Override
  82. public WildcardIndex named(String name) {
  83. super.named(name);
  84. return this;
  85. }
  86. /**
  87. * Unique option is not supported.
  88. *
  89. * @throws UnsupportedOperationException not supported for wildcard indexes.
  90. */
  91. @Override
  92. public Index unique() {
  93. throw new UnsupportedOperationException("Wildcard Index does not support 'unique'.");
  94. }
  95. /**
  96. * ttl option is not supported.
  97. *
  98. * @throws UnsupportedOperationException not supported for wildcard indexes.
  99. */
  100. @Override
  101. public Index expire(long seconds) {
  102. throw new UnsupportedOperationException("Wildcard Index does not support 'ttl'.");
  103. }
  104. /**
  105. * ttl option is not supported.
  106. *
  107. * @throws UnsupportedOperationException not supported for wildcard indexes.
  108. */
  109. @Override
  110. public Index expire(long value, TimeUnit timeUnit) {
  111. throw new UnsupportedOperationException("Wildcard Index does not support 'ttl'.");
  112. }
  113. /**
  114. * ttl option is not supported.
  115. *
  116. * @throws UnsupportedOperationException not supported for wildcard indexes.
  117. */
  118. @Override
  119. public Index expire(Duration duration) {
  120. throw new UnsupportedOperationException("Wildcard Index does not support 'ttl'.");
  121. }
  122. /**
  123. * Add fields to be included from indexing via {@code wildcardProjection}. <br />
  124. * This option is only allowed on {@link WildcardIndex#WildcardIndex() top level} wildcard indexes.
  125. *
  126. * @param paths must not be {@literal null}.
  127. * @return this.
  128. */
  129. public WildcardIndex wildcardProjectionInclude(String... paths) {
  130. for (String path : paths) {
  131. wildcardProjection.put(path, 1);
  132. }
  133. return this;
  134. }
  135. /**
  136. * Add fields to be excluded from indexing via {@code wildcardProjection}. <br />
  137. * This option is only allowed on {@link WildcardIndex#WildcardIndex() top level} wildcard indexes.
  138. *
  139. * @param paths must not be {@literal null}.
  140. * @return this.
  141. */
  142. public WildcardIndex wildcardProjectionExclude(String... paths) {
  143. for (String path : paths) {
  144. wildcardProjection.put(path, 0);
  145. }
  146. return this;
  147. }
  148. /**
  149. * Set the fields to be in-/excluded from indexing via {@code wildcardProjection}. <br />
  150. * This option is only allowed on {@link WildcardIndex#WildcardIndex() top level} wildcard indexes.
  151. *
  152. * @param includeExclude must not be {@literal null}.
  153. * @return this.
  154. */
  155. public WildcardIndex wildcardProjection(Map<String, Object> includeExclude) {
  156. wildcardProjection.putAll(includeExclude);
  157. return this;
  158. }
  159. private String getTargetFieldName() {
  160. return StringUtils.hasText(fieldName) ? (fieldName + ".$**") : "$**";
  161. }
  162. @Override
  163. public Document getIndexKeys() {
  164. return new Document(getTargetFieldName(), 1);
  165. }
  166. @Override
  167. public Document getIndexOptions() {
  168. Document options = new Document(super.getIndexOptions());
  169. if (!CollectionUtils.isEmpty(wildcardProjection)) {
  170. options.put("wildcardProjection", new Document(wildcardProjection));
  171. }
  172. return options;
  173. }
  174. }