Spring Data MongoDB - Indeks, Anotasi dan Penukar

1. Gambaran keseluruhan

Tutorial ini akan meneroka beberapa ciri utama Spring Data MongoDB - pengindeksan, anotasi umum dan penukar.

2. Indeks

2.1. @Indeks

Anotasi ini menandakan medan sebagai diindeks dalam MongoDB:

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

Sekarang bidang nama diindeks - mari kita lihat indeks di MongoDB:

db.user.getIndexes();

Inilah yang kami ada di peringkat pangkalan data:

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

Seperti yang anda lihat, kami mempunyai dua indeks - salah satunya adalah _id - yang dibuat secara lalai kerana anotasi @Id dan yang kedua adalah bidang nama kami .

2.2. Buat Indeks Secara Berprogram

Kami juga dapat membuat indeks secara terprogram:

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

Kami sekarang telah membuat indeks untuk nama bidang dan hasilnya akan sama seperti di bahagian sebelumnya.

2.3. Indeks Kompaun

MongoDB menyokong indeks kompaun, di mana struktur indeks tunggal menyimpan rujukan ke pelbagai bidang.

Mari lihat contoh ringkas menggunakan indeks kompaun:

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

Kami membuat indeks kompaun dengan e - mel dan bidang umur . Sekarang mari kita periksa indeks sebenar:

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

Perhatikan bahawa medan DBRef tidak dapat ditandai dengan @Index - medan itu hanya boleh menjadi sebahagian daripada indeks kompaun.

3. Anotasi Biasa

3.1 @ Sedang

Seperti yang anda jangkakan, anotasi sederhana ini tidak termasuk bidang yang berterusan dalam pangkalan data:

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

Mari masukkan pengguna dengan bidang tetapan tahunOfBirth :

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

Sekarang jika kita melihat keadaan pangkalan data, kita melihat bahawa tahunOfBirth yang difailkan tidak disimpan:

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

Oleh itu, jika kita membuat pertanyaan dan menyemak:

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

Hasilnya akan terbatal .

3.2. @Field

@Field menunjukkan kunci yang akan digunakan untuk bidang dalam dokumen JSON:

@Field("email") private EmailAddress emailAddress; 

Sekarang emailAddress akan disimpan dalam pangkalan data menggunakan e - mel utama :

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

Dan keadaan pangkalan data:

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

3.3. @PersistenceConstructor dan @Value

@PersistenceConstructor menandakan konstruktor, bahkan yang dilindungi pakej, menjadi konstruktor utama yang digunakan oleh logik kegigihan. Argumen konstruktor dipetakan dengan nama ke nilai utama dalam DBObject yang diambil .

Mari lihat konstruktor ini untuk kelas Pengguna kami :

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

Perhatikan penggunaan anotasi Spring @Value standard di sini. Dengan bantuan penjelasan ini, kita dapat menggunakan Spring Expressions untuk mengubah nilai kunci yang diambil dari pangkalan data sebelum digunakan untuk membina objek domain. Itu adalah ciri yang sangat kuat dan sangat berguna di sini.

Dalam contoh kita jika usia tidak ditetapkan bahawa ia akan ditetapkan ke 0 secara lalai.

Mari kita lihat bagaimana ia berfungsi:

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

Our database will look:

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

So the age field is null, but when we query the document and retrieve age:

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

The result will be 0.

4. Converters

Let's now take a look at another very useful feature in Spring Data MongoDB – converters, and specifically at the MongoConverter.

This is used to handle the mapping of all Java types to DBObjects when storing and querying these objects.

We have two options – we can either work with MappingMongoConverter – or SimpleMongoConverter in earlier versions (this was deprecated in Spring Data MongoDB M3 and its functionality has been moved into MappingMongoConverter).

Or we can write our own custom converter. To do that, we would need to implement the Converter interface and register the implementation in MongoConfig.

Let's look at a quick example. As you've seen in some of the JSON output here, all objects saved in a database have the field _class which is saved automatically. If however we'd like to skip that particular field during persistence, we can do that using a MappingMongoConverter.

First – here's the custom converter implementation:

@Component public class UserWriterConverter implements Converter { @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; } }

Notice how we can easily hit the goal of not persisting _class by specifically removing the field directly here.

Now we need to register the custom converter:

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

We can of course achieve the same result with XML configuration as well, if we need to:

Now, when we save a new user:

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

The resulting document in the database no longer contains the class information:

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

5. Conclusion

In this tutorial we've covered some core concepts of working with Spring Data MongoDB – indexing, common annotations and converters.

The implementation of all these examples and code snippets can be found in my github project.