sql >> Database teknologi >  >> NoSQL >> MongoDB

Spring Data MongoDB – Indekser, annoteringer og konvertere

1. Oversigt

I denne øvelse vil vi udforske nogle af kernefunktionerne i Spring Data MongoDB – indeksering, almindelige annoteringer og konvertere.

2. Indeks

2.1. @Indekseret

Denne annotation markerer feltet som indekseret i MongoDB:

@QueryEntity@Documentpublic klasse Bruger { @Indexed private String name; ... } 

Nu hvor navnet feltet er indekseret – lad os se på indekserne i MongoDB shell:

db.user.getIndex(); 

Her er, hvad vi får:

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

Vi kan blive overraskede over, at der ikke er noget tegn på navnet felt hvor som helst!

Dette skyldes, at fra Spring Data MongoDB 3.0 er automatisk indeksoprettelse deaktiveret som standard .

Vi kan dog ændre denne adfærd ved eksplicit at tilsidesætte autoIndexCreation() metode i vores MongoConfig :

public class MongoConfig udvider AbstractMongoClientConfiguration {// resten af ​​konfigurationen går her @Override protected boolean autoIndexCreation() { return true; }} 

Lad os igen tjekke indekserne i MongoDB shell:

[ { "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 denne gang to indekser – et af dem er _id – som blev oprettet som standard på grund af @Id annotering og den anden er vores navn felt.

Alternativt,hvis vi bruger Spring Boot, kunne vi indstille spring.data.mongodb.auto-index-creation ejendom til sand .

2.2. Opret et indeks programmatisk

Vi kan også oprette et indeks programmatisk:

mongoOps.indexOps(User.class). sureIndex(new Index().on("navn", Direction.ASC)); 

Vi har nu oprettet et indeks for feltet navn og resultatet bliver det samme som i forrige afsnit.

2.3. Sammensatte indekser

MongoDB understøtter sammensatte indekser, hvor en enkelt indeksstruktur indeholder referencer til flere felter.

Lad os se et hurtigt eksempel ved hjælp af sammensatte indekser:

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

Vi oprettede et sammensat indeks med e-mail og alder felter. Lad os nu se de faktiske indekser:

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

Bemærk, at en DBRef felt kan ikke markeres med @Index – det felt kan kun være en del af et sammensat indeks.

3. Almindelige anmærkninger

3.1. @Forbigående

Som vi kunne forvente, udelukker denne simple annotation feltet fra at blive ved med i databasen:

offentlig klassebruger { @Transient privat Integer yearOfBirth; 
 // standard getter og setter} 

Lad os indsætte bruger med indstillingsfeltet Fødselsår :

Bruger bruger =ny bruger();user.setName("Alex");user.setYearOfBirth(1985);mongoTemplate.insert(user); 

Hvis vi nu ser på databasens tilstand, ser vi, at det indsendte fødselsår blev ikke gemt:

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

Så hvis vi forespørger og tjekker:

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

Resultatet bliver null .

3.2. @Field

@Field angiver den nøgle, der skal bruges til feltet i JSON-dokumentet:

@Field("email")privat e-mailadresse e-mailadresse; 

Nu emailAddress vil blive gemt i databasen ved hjælp af nøglen e-mail:

Brugerbruger =ny bruger();bruger.sætNavn("Brendan");E-mailadresse-e-mailadresse =ny e-mailadresse();e-mailadresse.setValue("[email protected]");bruger.sætE-mailadresse(e-mailadresse);mongoTemplate.insert(bruger); 

Og databasens tilstand:

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

3.3. @PersistenceConstructor og @Værdi

@PersistenceConstructor markerer en konstruktør, selv en der er pakkebeskyttet, for at være den primære konstruktør, der bruges af persistenslogikken. Konstruktørargumenterne er afbildet efter navn til nøgleværdierne i det hentede DBObject .

Lad os se på denne konstruktør for vores Bruger klasse:

@PersistenceConstructorpublic User(String name, @Value("#root.age ?:0") Heltalsalder, EmailAddress emailAddress) { this.name =name; denne.alder =alder; this.emailAddress =emailAddress;} 

Bemærk brugen af ​​standard Spring @Value anmærkning her. Det er ved hjælp af denne annotation, at vi kan bruge Spring Expressions til at transformere en nøgles værdi hentet fra databasen, før den bruges til at konstruere et domæneobjekt. Det er en meget kraftfuld og meget nyttig funktion her.

I vores eksempel hvis alder ikke er indstillet, sættes den til 0 som standard.

Lad os nu se, hvordan det virker:

Bruger bruger =ny bruger();user.setName("Alex");mongoTemplate.insert(bruger); 

Vores database vil se ud:

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

Altså alderen feltet er null , men når vi forespørger i dokumentet og henter alder :

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

Resultatet bliver 0.

4. Konvertere

Lad os nu tage et kig på en anden meget nyttig funktion i Spring Data MongoDB – konvertere, og specifikt på MongoConverter .

Dette bruges til at håndtere tilknytningen af ​​alle Java-typer til DBObjects når du gemmer og forespørger disse objekter.

Vi har to muligheder – vi kan enten arbejde med MappingMongoConverter – eller SimpleMongoConverter i tidligere versioner (dette blev forældet i Spring Data MongoDB M3, og dets funktionalitet er blevet flyttet til MappingMongoConverter ).

Eller vi kan skrive vores egen brugerdefinerede konverter. For at gøre det skal vi implementere konverteren interface og registrer implementeringen i MongoConfig.

Lad os se på et hurtigt eksempel . Som vi har set i nogle af JSON-outputtet her, har alle objekter gemt i en database feltet _class som gemmes automatisk. Hvis vi dog gerne vil springe det pågældende felt over under persistens, kan vi gøre det ved hjælp af en MappingMongoConverter .

Først – her er den tilpassede konverterimplementering:

@Componentpublic class UserWriterConverter implementerer Converter { @Override public DBObject convert(User user) { DBObject dbObject =new BasicDBObject(); dbObject.put("navn", bruger.getNavn()); dbObject.put("alder", bruger.getAlder()); if (bruger.getEmailAddress() !=null) { DBObject emailDbObject =new BasicDBObject(); emailDbObject.put("værdi", bruger.getEmailAddress().getValue()); dbObject.put("email", emailDbObject); } dbObject.removeField("_klasse"); returnere dbObject; }} 

Læg mærke til, hvordan vi nemt kan nå målet om ikke at blive ved med _class ved specifikt at fjerne feltet direkte her.

Nu skal vi registrere den brugerdefinerede konverter:

private List> converters =new ArrayList>();@Overridepublic MongoCustomConversions customConversions() { converters.add(new UserWriterConverter()); returnere nye MongoCustomConversions(converters);} 

Vi kan selvfølgelig også opnå det samme resultat med XML-konfiguration, hvis vi skal:

     

Nu, når vi gemmer en ny bruger:

Brugerbruger =ny bruger();user.setName("Chris");mongoOps.insert(bruger); 

Det resulterende dokument i databasen indeholder ikke længere klasseoplysningerne:

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

  1. er der en måde at få klientens IP i redis?

  2. Mongoose befolker vs objektnesting

  3. Demokratisk kø i Sidekiq

  4. Bringe transaktionssupport til Cloudera Operational Database