sql >> Databasteknik >  >> NoSQL >> MongoDB

Spring Data MongoDB – Index, anteckningar och omvandlare

1. Översikt

I den här handledningen kommer vi att utforska några av kärnfunktionerna i Spring Data MongoDB – indexering, vanliga kommentarer och omvandlare.

2. Index

2.1. @Indexerad

Den här kommentaren markerar fältet som indexerat i MongoDB:

@QueryEntity
@Document
public class User {
    @Indexed
    private String name;
    
    ... 
}

Nu när namnet fältet är indexerat – låt oss ta en titt på indexen i MongoDB-skalet:

db.user.getIndexes();

Det här är vad vi får:

[
    {
        "v" : 1,
        "key" : {
             "_id" : 1
         },
        "name" : "_id_",
        "ns" : "test.user"
    }
]

Vi kan bli förvånade över att det inte finns några tecken på namnet fält var som helst!

Detta beror på att från Spring Data MongoDB 3.0 är automatisk indexskapande avstängd som standard .

Vi kan dock ändra det beteendet genom att uttryckligen åsidosätta autoIndexCreation() metod i vår MongoConfig :

public class MongoConfig extends AbstractMongoClientConfiguration {

    // rest of the config goes here

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

Låt oss återigen kolla in indexen i MongoDB-skalet:

[
    {
        "v" : 1,
        "key" : {
             "_id" : 1
         },
        "name" : "_id_",
        "ns" : "test.user"
    },
    {
         "v" : 1,
         "key" : {
             "name" : 1
          },
          "name" : "name",
          "ns" : "test.user"
     }
]

Som vi kan se har vi den här gången två index – ett av dem är _id – som skapades som standard på grund av @Id anteckning och den andra är vårt namn fält.

Alternativt,om vi använder Spring Boot kan vi ställa in spring.data.mongodb.auto-index-creation egenskapen true .

2.2. Skapa ett index programmatiskt

Vi kan också skapa ett index programmatiskt:

mongoOps.indexOps(User.class).
  ensureIndex(new Index().on("name", Direction.ASC));

Vi har nu skapat ett index för fältet namn och resultatet blir detsamma som i föregående avsnitt.

2.3. Sammansatta index

MongoDB stöder sammansatta index, där en enda indexstruktur innehåller referenser till flera fält.

Låt oss se ett snabbt exempel med sammansatta index:

@QueryEntity
@Document
@CompoundIndexes({
    @CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}")
})
public class User {
    //
}

Vi skapade ett sammansatt index med e-post och ålder fält. Låt oss nu kolla in de faktiska indexen:

{
    "v" : 1,
    "key" : {
        "email.id" : 1,
        "age" : 1
    },
    "name" : "email_age",
    "ns" : "test.user"
}

Observera att en DBRef fältet kan inte markeras med @Index – det fältet kan bara vara en del av ett sammansatt index.

3. Vanliga kommentarer

3.1. @Transient

Som vi förväntar oss utesluter denna enkla anteckning att fältet finns kvar i databasen:

public class User {
    
    @Transient
    private Integer yearOfBirth;
    // standard getter and setter

}

Låt oss infoga användare med inställningsfältet födelseår :

User user = new User();
user.setName("Alex");
user.setYearOfBirth(1985);
mongoTemplate.insert(user);

Om vi ​​nu tittar på databasens tillstånd ser vi att det inlämnade födelseåret sparades inte:

{
    "_id" : ObjectId("55d8b30f758fd3c9f374499b"),
    "name" : "Alex",
    "age" : null
}

Så om vi frågar och kontrollerar:

mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getYearOfBirth()

Resultatet blir null .

3.2. @Field

@Field indikerar nyckeln som ska användas för fältet i JSON-dokumentet:

@Field("email")
private EmailAddress emailAddress;

Nu e-postadress kommer att sparas i databasen med nyckeln e-post:

User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("[email protected]");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);

Och tillståndet för databasen:

{
    "_id" : ObjectId("55d076d80bad441ed114419d"),
    "name" : "Brendan",
    "age" : null,
    "email" : {
        "value" : "[email protected]"
    }
}

3.3. @PersistenceConstructor och @Value

@PersistenceConstructor markerar en konstruktor, även en som är paketskyddad, att vara den primära konstruktören som används av persistenslogiken. Konstruktorargumenten mappas efter namn till nyckelvärdena i det hämtade DBObject .

Låt oss titta på den här konstruktören för vår användare klass:

@PersistenceConstructor
public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) {
    this.name =  name;
    this.age = age;
    this.emailAddress =  emailAddress;
}

Lägg märke till användningen av standard Spring @Value anteckning här. Det är med hjälp av denna annotering som vi kan använda Spring Expressions för att transformera en nyckels värde som hämtas från databasen innan den används för att konstruera ett domänobjekt. Det är en mycket kraftfull och mycket användbar funktion här.

I vårt exempel om ålder inte är inställd kommer den att ställas till 0 som standard.

Låt oss nu se hur det fungerar:

User user = new User();
user.setName("Alex");
mongoTemplate.insert(user);

Vår databas kommer att se ut:

{
    "_id" : ObjectId("55d074ca0bad45f744a71318"),
    "name" : "Alex",
    "age" : null
}

Alltså åldern fältet är null , men när vi frågar efter dokumentet och hämtar ålder :

mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();

Resultatet blir 0.

4. Konverterare

Låt oss nu ta en titt på en annan mycket användbar funktion i Spring Data MongoDB – omvandlare, och specifikt på MongoConverter .

Detta används för att hantera mappningen av alla Java-typer till DBObjects när du lagrar och frågar efter dessa objekt.

Vi har två alternativ – vi kan antingen arbeta med MappingMongoConverter – eller SimpleMongoConverter i tidigare versioner (detta föråldrades i Spring Data MongoDB M3 och dess funktionalitet har flyttats till MappingMongoConverter ).

Eller så kan vi skriva vår egen anpassade omvandlare. För att göra det skulle vi behöva implementera omvandlaren gränssnitt och registrera implementeringen i MongoConfig.

Låt oss titta på ett snabbt exempel . Som vi har sett i en del av JSON-utdata här, har alla objekt som sparats i en databas fältet _class som sparas automatiskt. Om vi ​​däremot skulle vilja hoppa över det specifika fältet under ihållande, kan vi göra det med en MappingMongoConverter .

Först – här är implementeringen av anpassad omvandlare:

@Component
public class UserWriterConverter implements Converter<User, DBObject> {
    @Override
    public DBObject convert(User user) {
        DBObject dbObject = new BasicDBObject();
        dbObject.put("name", user.getName());
        dbObject.put("age", user.getAge());
        if (user.getEmailAddress() != null) {
            DBObject emailDbObject = new BasicDBObject();
            emailDbObject.put("value", user.getEmailAddress().getValue());
            dbObject.put("email", emailDbObject);
        }
        dbObject.removeField("_class");
        return dbObject;
    }
}

Lägg märke till hur vi enkelt kan nå målet att inte bestå _class genom att specifikt ta bort fältet direkt här.

Nu måste vi registrera den anpassade omvandlaren:

private List<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();

@Override
public MongoCustomConversions customConversions() {
    converters.add(new UserWriterConverter());
    return new MongoCustomConversions(converters);
}

Vi kan naturligtvis uppnå samma resultat med XML-konfiguration också, om vi behöver:

<bean id="mongoTemplate" 
  class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongo" ref="mongo"/>
    <constructor-arg ref="mongoConverter" />
    <constructor-arg name="databaseName" value="test"/>
</bean>

<mongo:mapping-converter id="mongoConverter" base-package="org.baeldung.converter">
    <mongo:custom-converters base-package="com.baeldung.converter" />
</mongo:mapping-converter>

Nu, när vi sparar en ny användare:

User user = new User();
user.setName("Chris");
mongoOps.insert(user);

Det resulterande dokumentet i databasen innehåller inte längre klassinformationen:

{
    "_id" : ObjectId("55cf09790bad4394db84b853"),
    "name" : "Chris",
    "age" : null
}

  1. Redis autocomplete

  2. Så här gör du:Hantera HBase-data via Hue

  3. Hur lagrar man sorterad uppsättning objekt i redis?

  4. Redis Cross Slot-fel