14

I have the following object structure:

@Document(collection = "user")
@TypeAlias("user")
public class User {
    @Id
    private ObjectId id;
    private Contact info = new Contact();
}

and here is the Contact pojo:

public class Contact {
    @Indexed(unique = true)
    private String mail;
}

But for some reasons not known to me, I don't see Spring-data creating a unique index for the property info.mail

To summarize, I have this json structure of user object: {_id:xxxxx,info:{mail:"abc@xyz.shoes"}}

And I want to create a unique index on info.mail using Spring data with the above pojo structure. Please help.

Ashot Karakhanyan
  • 2,804
  • 3
  • 23
  • 28
hellojava
  • 4,904
  • 9
  • 30
  • 38

4 Answers4

24

As far as I remember, annotating embedded fields with @Indexed will not work. @CompoundIndex is the way to go:

@Document(collection = "user")
@TypeAlias("user")
@CompoundIndexes({
    @CompoundIndex(name = "contact_email", def = "{ 'contact.mail': 1 }", unique = true)
})
public class User {
    @Id
    private ObjectId id;
    private Contact info = new Contact();
}
Maciej Walkowiak
  • 12,372
  • 59
  • 63
  • Could you please guide me here : https://stackoverflow.com/questions/61948943/spring-data-mongo-apply-unique-combination-fields-in-embedded-document – PAA May 22 '20 at 06:32
  • If necessary, you may have to use the `@Field` annotation as described [here](https://stackoverflow.com/a/14054004/5943840). But it works fine without it for me if I remove the outer `@CompoundIndexes` tag and only use the `@CompoundIndex` annotation. – Raphael Apr 30 '21 at 20:19
10

In my case I had a fresh spring boot application 2.3.0 with just @Document, @Id and @Indexed annotations. I was able to retrieve and insert documents but it refused to create the index other than the PK. Finally I figured that there is a property that you need to enable.

spring.data.mongodb.auto-index-creation = true

As a matter of fact it even works on nested objects without @Document annotation.

Hope this helps :)

Xenobius
  • 101
  • 1
  • 6
  • For 'AbstractMongoClientConfiguration', that is 'public boolean autoIndexCreation() ' which is false by default. – learner Jan 27 '21 at 11:34
7

Obsolete answer, this was with and older version of mongodb 1.x.


Had the same issue, it seems that your Contact class is missing the @Document annotation i.e.

@Document
public class Contact {
    @Indexed(unique = true)
    private String mail;
}

Should work, quote from the spring mongodb reference

Automatic index creation is only done for types annotated with @Document.

cristobal
  • 462
  • 5
  • 14
  • 2
    I think that any embedded document doesn't require @Document because it's not a real document, but just a filed of a Document. – db80 Feb 12 '16 at 11:16
  • Sure, but you still have to hint the Spring MongoDB DSL implementation about how to transform and use the classes it it supposed to *index*. The Spring MongoDB will parse the classes internally for every class that use the `@Document` annotation and apply the `@Indexed` option for it. You can apply automatic `index` through the *mongo* console or via *java code* if you want. But if you want to benefit from the automatic stuff that Spring does for you, you just have to follow the rules in the documentation :P – cristobal Feb 12 '16 at 12:53
  • Otherwise it would be kind of hard for the *Spring Mongo* implementation, to just parse all the java files in the embedded code and check all the fields for every class that is annotated with the `@Indexed` annotation. The larger the code base the more time it would take. So the reason they have `@Document` is to hint the *Spring Mongo* implementation about which files to check for and apply the `@Indexed` option if set. – cristobal Feb 12 '16 at 12:55
  • 1
    I meant that you don't need to add any annotation in the embedded document. If you need to index a field of an embedded document you should use @CompoundIndex on the parent class. – db80 Feb 12 '16 at 15:00
  • Kind of find it strange the docs for *Spring Mongo* clearly show all the examples of the usage `@CompoundIndex` in conjunction with usage of the `@Docucment` annotation. – cristobal Feb 12 '16 at 15:04
  • Ok i get what you are saying extend a parent class with a `@Document` annotation. Sure that would work but that's more a coding/style choice. I Prefer to have each base `@Document` class that goes into *mongodb* as a final class that does not have any inheritance. – cristobal Feb 12 '16 at 15:08
  • @cristobal Why is that index is created each time a Mongo Connection is established using Indexed on a class property? Doesn't this cause an overload on the Database? I can see in the logs that indexes are created each time. – Adnan Jan 09 '19 at 11:56
  • @Adnan the spring mongo db driver i was using then is for an old mongo db impl. As far from your question i can't remember that happening. It may happen that this answer does not apply to the spring mongodb driver and the mongodb version you are currently using. – cristobal Jan 09 '19 at 14:17
  • 1
    @Adnan sorry for the late reply, this answer was for an older mongo db driver and I have marked the answer as obsolete. – cristobal Apr 23 '20 at 13:37
0

Extending @Xenobius's answer:

If any configuration extending AbstractMongoClientConfiguration is set, MongoMappingContext will back off. The result is:

spring.data.mongodb.auto-index-creation = true will not be effective

You will need add this into your own configuration:

    @Override
    protected boolean autoIndexCreation() {
        return true;
    }

ref: https://github.com/spring-projects/spring-boot/issues/28478#issuecomment-954627106