1. Ikhtisar
Dalam tutorial ini kita akan menjelajahi beberapa fitur inti dari Spring Data MongoDB – pengindeksan, anotasi umum, dan konverter.
2. Indeks
2.1. @Diindeks
Anotasi ini menandai bidang sebagai diindeks di MongoDB:
@QueryEntity
@Document
public class User {
@Indexed
private String name;
...
}
Sekarang nama bidang diindeks – mari kita lihat indeks di shell MongoDB:
db.user.getIndexes();
Inilah yang kami dapatkan:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.user"
}
]
Kami mungkin terkejut tidak ada tanda-tanda nama lapangan di mana saja!
Ini karena, pada Spring Data MongoDB 3.0, pembuatan indeks otomatis dimatikan secara default .
Namun, kita dapat mengubah perilaku itu dengan secara eksplisit mengganti autoIndexCreation() metode di MongoConfig our kami :
public class MongoConfig extends AbstractMongoClientConfiguration {
// rest of the config goes here
@Override
protected boolean autoIndexCreation() {
return true;
}
}
Mari kita periksa lagi indeks di shell MongoDB:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.user"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"name" : "name",
"ns" : "test.user"
}
]
Seperti yang kita lihat, kali ini kita memiliki dua indeks – salah satunya adalah _id – yang dibuat secara default karena @Id anotasi dan yang kedua adalah nama kami lapangan.
Atau, jika kita menggunakan Spring Boot, kita dapat menyetel spring.data.mongodb.auto-index-creation properti ke benar .
2.2. Buat Indeks Secara Terprogram
Kami juga dapat membuat indeks secara terprogram:
mongoOps.indexOps(User.class).
ensureIndex(new Index().on("name", Direction.ASC));
Kami sekarang telah membuat indeks untuk bidang nama dan hasilnya akan sama seperti pada bagian sebelumnya.
2.3. Indeks Gabungan
MongoDB mendukung indeks gabungan, di mana struktur indeks tunggal menyimpan referensi ke beberapa bidang.
Mari kita lihat contoh singkat menggunakan indeks gabungan:
@QueryEntity
@Document
@CompoundIndexes({
@CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}")
})
public class User {
//
}
Kami membuat indeks gabungan dengan email dan usia bidang. Sekarang mari kita periksa indeks yang sebenarnya:
{
"v" : 1,
"key" : {
"email.id" : 1,
"age" : 1
},
"name" : "email_age",
"ns" : "test.user"
}
Perhatikan bahwa DBRef bidang tidak dapat ditandai dengan @Index – bidang itu hanya dapat menjadi bagian dari indeks gabungan.
3. Anotasi Umum
3.1. @Transien
Seperti yang kami harapkan, anotasi sederhana ini mengecualikan bidang agar tidak disimpan di database:
public class User {
@Transient
private Integer yearOfBirth;
// standard getter and setter
}
Mari masukkan pengguna dengan bidang pengaturan yearOfBirth :
User user = new User();
user.setName("Alex");
user.setYearOfBirth(1985);
mongoTemplate.insert(user);
Sekarang jika kita melihat keadaan database, kita melihat bahwa file yearOfBirth . yang diajukan tidak disimpan:
{
"_id" : ObjectId("55d8b30f758fd3c9f374499b"),
"name" : "Alex",
"age" : null
}
Jadi jika kita menanyakan dan memeriksa:
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getYearOfBirth()
Hasilnya akan menjadi null .
3.2. @Field
@Field menunjukkan kunci yang akan digunakan untuk bidang dalam dokumen JSON:
@Field("email")
private EmailAddress emailAddress;
Sekarang alamat email akan disimpan dalam database menggunakan kunci email:
User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("[email protected]");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);
Dan status database:
{
"_id" : ObjectId("55d076d80bad441ed114419d"),
"name" : "Brendan",
"age" : null,
"email" : {
"value" : "[email protected]"
}
}
3.3. @PersistenceConstructor dan @Nilai
@PersistenceConstructor menandai konstruktor, bahkan konstruktor yang dilindungi paket, sebagai konstruktor utama yang digunakan oleh logika persistensi. Argumen konstruktor dipetakan menurut nama ke nilai kunci dalam DBObject . yang diambil .
Mari kita lihat konstruktor ini untuk Pengguna our kelas:
@PersistenceConstructor
public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) {
this.name = name;
this.age = age;
this.emailAddress = emailAddress;
}
Perhatikan penggunaan Spring standar @Value anotasi di sini. Dengan bantuan anotasi inilah kita dapat menggunakan Spring Expressions untuk mengubah nilai kunci yang diambil dari database sebelum digunakan untuk membangun objek domain. Itu adalah fitur yang sangat kuat dan sangat berguna di sini.
Dalam contoh kami jika usia tidak disetel, akan disetel ke 0 secara default.
Sekarang mari kita lihat cara kerjanya:
User user = new User();
user.setName("Alex");
mongoTemplate.insert(user);
Basis data kami akan terlihat:
{
"_id" : ObjectId("55d074ca0bad45f744a71318"),
"name" : "Alex",
"age" : null
}
Jadi usia kolom null , tetapi ketika kami menanyakan dokumen dan mengambil usia :
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();
Hasilnya adalah 0.
4. Pengonversi
Sekarang mari kita lihat fitur lain yang sangat berguna di Spring Data MongoDB – konverter, dan khususnya di MongoConverter .
Ini digunakan untuk menangani pemetaan semua tipe Java ke DBObjects saat menyimpan dan menanyakan objek ini.
Kami memiliki dua opsi – kami dapat bekerja dengan MappingMongoConverter – atau SimpleMongoConverter di versi sebelumnya (ini tidak digunakan lagi di Spring Data MongoDB M3 dan fungsinya telah dipindahkan ke MappingMongoConverter ).
Atau kita bisa menulis konverter kustom kita sendiri. Untuk melakukannya, kita perlu mengimplementasikan Converter antarmuka dan daftarkan implementasinya di MongoConfig.
Mari kita lihat contoh singkat . Seperti yang telah kita lihat di beberapa keluaran JSON di sini, semua objek yang disimpan dalam database memiliki bidang _class yang disimpan secara otomatis. Namun, jika kami ingin melewati bidang tertentu selama persistensi, kami dapat melakukannya menggunakan MappingMongoConverter .
Pertama – inilah implementasi konverter kustom:
@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;
}
}
Perhatikan bagaimana kita dapat dengan mudah mencapai tujuan untuk tidak bertahan _class dengan menghapus bidang secara khusus langsung di sini.
Sekarang kita perlu mendaftarkan konverter kustom:
private List<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();
@Override
public MongoCustomConversions customConversions() {
converters.add(new UserWriterConverter());
return new MongoCustomConversions(converters);
}
Kita tentu saja dapat mencapai hasil yang sama dengan konfigurasi XML juga, jika kita perlu:
<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>
Sekarang, ketika kita menyimpan pengguna baru:
User user = new User();
user.setName("Chris");
mongoOps.insert(user);
Dokumen yang dihasilkan dalam database tidak lagi berisi informasi kelas:
{
"_id" : ObjectId("55cf09790bad4394db84b853"),
"name" : "Chris",
"age" : null
}