MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Impor Data ke MongoDB Dari File JSON Menggunakan Java

1. Pendahuluan

Dalam tutorial ini, kita akan belajar cara membaca data JSON dari file dan mengimpornya ke MongoDB menggunakan Spring Boot. Ini dapat berguna karena berbagai alasan:memulihkan data, menyisipkan data baru secara massal, atau memasukkan nilai default. MongoDB menggunakan JSON secara internal untuk menyusun dokumennya, jadi tentu saja, itulah yang akan kami gunakan untuk menyimpan file yang dapat diimpor. Menjadi teks biasa, strategi ini juga memiliki keuntungan karena mudah dikompresi.

Selain itu, kita akan belajar bagaimana memvalidasi file input kita terhadap jenis kustom kita bila diperlukan. Terakhir, kami akan memaparkan API sehingga kami dapat menggunakannya selama waktu proses di aplikasi web kami.

2. Dependensi

Mari tambahkan dependensi Spring Boot ini ke pom.xml our kita :

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

Kami juga akan membutuhkan instance MongoDB yang sedang berjalan, yang memerlukan application.properties yang dikonfigurasi dengan benar berkas.

3. Mengimpor String JSON

Cara paling sederhana untuk mengimpor JSON ke MongoDB adalah dengan mengubahnya menjadi “org.bson.Document ” objek terlebih dahulu. Kelas ini mewakili dokumen MongoDB generik tanpa tipe spesifik. Oleh karena itu, kita tidak perlu khawatir membuat repositori untuk semua jenis objek yang mungkin kita impor.

Strategi kami mengambil JSON (dari file, sumber daya, atau string), mengubahnya menjadi Dokumen s, dan menyimpannya menggunakan MongoTemplate . Operasi batch umumnya berkinerja lebih baik karena jumlah perjalanan pulang pergi berkurang dibandingkan dengan memasukkan setiap objek satu per satu.

Yang terpenting, kami akan menganggap input kami hanya memiliki satu objek JSON per jeda baris. Dengan begitu, kita dapat dengan mudah membatasi objek kita. Kami akan merangkum fungsionalitas ini ke dalam dua kelas yang akan kami buat:ImportUtils dan ImportJsonService . Mari kita mulai dengan kelas layanan kami:

@Service
public class ImportJsonService {

    @Autowired
    private MongoTemplate mongo;
}

Selanjutnya, mari tambahkan metode yang mem-parsing baris JSON ke dalam dokumen:

private List<Document> generateMongoDocs(List<String> lines) {
    List<Document> docs = new ArrayList<>();
    for (String json : lines) {
        docs.add(Document.parse(json));
    }
    return docs;
}

Kemudian kami menambahkan metode yang menyisipkan daftar Dokumen objek ke dalam koleksi . yang diinginkan . Juga, mungkin sebagian operasi batch gagal. Dalam hal ini, kami dapat mengembalikan jumlah dokumen yang dimasukkan dengan memeriksa penyebab dari pengecualian :

private int insertInto(String collection, List<Document> mongoDocs) {
    try {
        Collection<Document> inserts = mongo.insert(mongoDocs, collection);
        return inserts.size();
    } catch (DataIntegrityViolationException e) {
        if (e.getCause() instanceof MongoBulkWriteException) {
            return ((MongoBulkWriteException) e.getCause())
              .getWriteResult()
              .getInsertedCount();
        }
        return 0;
    }
}

Akhirnya, mari kita gabungkan metode-metode itu. Yang ini mengambil input dan mengembalikan string yang menunjukkan berapa banyak baris yang dibaca vs. berhasil dimasukkan:

public String importTo(String collection, List<String> jsonLines) {
    List<Document> mongoDocs = generateMongoDocs(jsonLines);
    int inserts = insertInto(collection, mongoDocs);
    return inserts + "/" + jsonLines.size();
}

4. Kasus Penggunaan

Sekarang setelah kita siap untuk memproses input, kita dapat membangun beberapa use case. Mari buat ImportUtils kelas untuk membantu kami dengan itu. Kelas ini akan bertanggung jawab untuk mengubah input menjadi baris JSON. Ini hanya akan berisi metode statis. Mari kita mulai dengan membaca String simple sederhana :

public static List<String> lines(String json) {
    String[] split = json.split("[\\r\\n]+");
    return Arrays.asList(split);
}

Karena kami menggunakan jeda baris sebagai pembatas, regex berfungsi dengan baik untuk memecah string menjadi beberapa baris. Regex ini menangani akhiran baris Unix dan Windows. Selanjutnya, metode untuk mengubah File menjadi daftar string:

public static List<String> lines(File file) {
    return Files.readAllLines(file.toPath());
}

Demikian pula, kami menyelesaikan dengan metode untuk mengubah sumber daya classpath menjadi daftar:

public static List<String> linesFromResource(String resource) {
    Resource input = new ClassPathResource(resource);
    Path path = input.getFile().toPath();
    return Files.readAllLines(path);
}

4.1. Impor File Saat Memulai Dengan CLI

Dalam kasus penggunaan pertama kami, kami akan menerapkan fungsionalitas untuk mengimpor file melalui argumen aplikasi. Kami akan memanfaatkan Spring Boot ApplicationRunner antarmuka untuk melakukan ini pada saat boot. Misalnya, kita dapat membaca parameter baris perintah untuk menentukan file yang akan diimpor:

@SpringBootApplication
public class SpringBootJsonConvertFileApplication implements ApplicationRunner {
    private static final String RESOURCE_PREFIX = "classpath:";

    @Autowired
    private ImportJsonService importService;

    public static void main(String ... args) {
        SpringApplication.run(SpringBootPersistenceApplication.class, args);
    }

    @Override
    public void run(ApplicationArguments args) {
        if (args.containsOption("import")) {
            String collection = args.getOptionValues("collection")
              .get(0);

            List<String> sources = args.getOptionValues("import");
            for (String source : sources) {
                List<String> jsonLines = new ArrayList<>();
                if (source.startsWith(RESOURCE_PREFIX)) {
                    String resource = source.substring(RESOURCE_PREFIX.length());
                    jsonLines = ImportUtils.linesFromResource(resource);
                } else {
                    jsonLines = ImportUtils.lines(new File(source));
                }
                
                String result = importService.importTo(collection, jsonLines);
                log.info(source + " - result: " + result);
            }
        }
    }
}

Menggunakan getOptionValues() kita dapat memproses satu atau lebih file. File-file ini dapat berasal dari classpath kami atau dari sistem file kami. Kami membedakannya menggunakan RESOURCE_PREFIX . Setiap argumen dimulai dengan “classpath: ” akan dibaca dari folder sumber daya kami, bukan dari sistem file. Setelah itu, semuanya akan diimpor ke koleksi yang diinginkan .

Mari mulai menggunakan aplikasi kita dengan membuat file di bawah src/main/resources/data.json.log :

{"name":"Book A", "genre": "Comedy"}
{"name":"Book B", "genre": "Thriller"}
{"name":"Book C", "genre": "Drama"}

Setelah membangun, kita dapat menggunakan contoh berikut untuk menjalankannya (jeda baris ditambahkan agar mudah dibaca). Dalam contoh kita, dua file akan diimpor, satu dari classpath, dan satu dari sistem file:

java -cp target/spring-boot-persistence-mongodb/WEB-INF/lib/*:target/spring-boot-persistence-mongodb/WEB-INF/classes \
  -Djdk.tls.client.protocols=TLSv1.2 \
  com.baeldung.SpringBootPersistenceApplication \
  --import=classpath:data.json.log \
  --import=/tmp/data.json \
  --collection=books

4.2. File JSON Dari Unggah HTTP POST

Selain itu, jika kita membuat Pengontrol REST, kita akan memiliki titik akhir untuk mengunggah dan mengimpor file JSON. Untuk itu, kita membutuhkan MultipartFile parameter:

@RestController
@RequestMapping("/import-json")
public class ImportJsonController {
    @Autowired
    private ImportJsonService service;

    @PostMapping("/file/{collection}")
    public String postJsonFile(@RequestPart("parts") MultipartFile jsonStringsFile, @PathVariable String collection)  {
        List<String> jsonLines = ImportUtils.lines(jsonStringsFile);
        return service.importTo(collection, jsonLines);
    }
}

Sekarang kita dapat mengimpor file dengan POST seperti ini, di mana “/tmp/data.json ” merujuk ke file yang ada:

curl -X POST http://localhost:8082/import-json/file/books -F "[email protected]/tmp/books.json"

4.3. Memetakan JSON ke Tipe Java Tertentu

Kami hanya menggunakan JSON, tidak terikat pada jenis apa pun, yang merupakan salah satu keuntungan bekerja dengan MongoDB. Sekarang kami ingin memvalidasi masukan kami. Dalam hal ini, mari tambahkan ObjectMapper dengan membuat perubahan ini pada layanan kami:

private <T> List<Document> generateMongoDocs(List<String> lines, Class<T> type) {
    ObjectMapper mapper = new ObjectMapper();

    List<Document> docs = new ArrayList<>();
    for (String json : lines) {
        if (type != null) {
            mapper.readValue(json, type);
        }
        docs.add(Document.parse(json));
    }
    return docs;
}

Dengan begitu, jika ketik parameter ditentukan, pemeta our kami akan mencoba mengurai string JSON kami sebagai tipe itu. Dan, dengan konfigurasi default, akan mengeluarkan pengecualian jika ada properti yang tidak dikenal. Berikut definisi kacang sederhana kami untuk bekerja dengan repositori MongoDB:

@Document("books")
public class Book {
    @Id
    private String id;
    private String name;
    private String genre;
    // getters and setters
}

Dan sekarang, untuk menggunakan versi yang ditingkatkan dari generator Dokumen kami, mari ubah metode ini juga:

public String importTo(Class<?> type, List<String> jsonLines) {
    List<Document> mongoDocs = generateMongoDocs(jsonLines, type);
    String collection = type.getAnnotation(org.springframework.data.mongodb.core.mapping.Document.class)
      .value();
    int inserts = insertInto(collection, mongoDocs);
    return inserts + "/" + jsonLines.size();
}

Sekarang, alih-alih meneruskan nama koleksi, kami melewati Kelas . Kami menganggapnya memiliki Dokumen anotasi seperti yang kami gunakan di Buku kami , sehingga dapat mengambil nama koleksi. Namun, karena anotasi dan Dokumen kelas memiliki nama yang sama, kita harus menentukan seluruh paket.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. mongodb temukan dengan membandingkan nilai bidang

  2. Persentase kondisi ATAU yang cocok di mongodb

  3. MongoDB $maks

  4. Salin/Klon Koleksi di MongoDB

  5. Pencarian agregasi Mongodb dengan kondisi