Introduce EzyMongo

Updated at 1699803552000

1. Introduce EzyMongo

EzyMongo (Easy going to Mongo Interaction) is a framework support to interact to MongoDB, It supports:
  1. Transparently map your Java entities to MongoDB documents and back.
  2. Query, update, delete and aggregation by query string.
  3. Annotation driven.

2. Structure of EzyMongo

  1. Database Context: wraps MongoClient, DataBinding. Manages repositiors, QueryManager and DataSerializers. Provides function to get repostiories, queries and serializers
  2. Repostiories: Manages all repostiores by name and type
  3. QueryManager: Manages all queries, collects queries from annotations and deverloper set
  4. DataSerializers: Manages all data serializers and deserializers, provide a way to allow deverloper custom and set their serializers and deverlopers
  5. Repostiory: converts queries, data and calls to MongoDB

3. Install EzyMongo

1. To create EzyMongo we need add dependency

<dependency>
    <groupId>com.tvd12</groupId>
    <artifactId>ezydata-mongodb</artifactId>
    <version>1.2.8</version>
</dependency>

The latest version can be found in the Maven Central repository. 2. To use EzyMongo you need config to create repositories You can use ezyfox-boot-autoconfigure by add to your pom.xml:

<dependency>
    <groupId>com.tvd12</groupId>
    <artifactId>ezyfox-boot-autoconfigure</artifactId>
    <version>1.1.0</version>
</dependency>

Or because with some reason, you can not use ezyfox-boot-autoconfigure you can config like this:

    import com.mongodb.MongoClient;
    import com.tvd12.ezydata.database.EzyDatabaseContext;
    import com.tvd12.ezydata.mongodb.EzyMongoDatabaseContextBuilder;
    import com.tvd12.ezydata.mongodb.loader.EzySimpleMongoClientLoader;
    import com.tvd12.ezyfox.annotation.EzyProperty;
    import com.tvd12.ezyfox.bean.EzyBeanConfig;
    import com.tvd12.ezyfox.bean.EzyPackagesToScanAware;
    import com.tvd12.ezyfox.bean.EzySingletonFactory;
    import com.tvd12.ezyfox.bean.EzySingletonFactoryAware;
    import com.tvd12.ezyfox.bean.annotation.EzyConfigurationBefore;
    import com.tvd12.ezyfox.util.EzyPropertiesAware;
    import lombok.Setter;
    import java.util.Map;
    import java.util.Properties;
    @Setter
    @EzyConfigurationBefore
    public class EzyMongoConfiguration implements
            EzyBeanConfig,
            EzyPropertiesAware,
            EzySingletonFactoryAware {
        @EzyProperty("database.mongo.database")
        private String databaseName;
        private Properties properties;
        private EzySingletonFactory singletonFactory;
        @Override
        public void config() {
            EzyDatabaseContext databaseContext = newMongodbDatabaseContext();
            Map repos = databaseContext.getRepositoriesByName();
            for (String repoName : repos.keySet()) {
                singletonFactory.addSingleton(repoName, repos.get(repoName));
            }
        }
        private EzyDatabaseContext newMongodbDatabaseContext() {
            EzyMongoDatabaseContextBuilder builder = new EzyMongoDatabaseContextBuilder()
                    .properties(properties)
                    .scan("your_package_to_scan")
                    .mongoClient(newMongoClient())
                    .databaseName(databaseName);
            return builder.build();
        }
        protected MongoClient newMongoClient() {
            return EzySimpleMongoClientLoader.load(properties);
        }
    }

3. You can add to your configuration file like this:

    # for application.yaml
    database:
      mongo:
        uri: mongodb://ezydata_mongo:ezydata_mongo@localhost:27017/ezydata-mongo
        database: ezydata-mongo
        collection:
          naming:
            case: UNDERSCORE
            ignored_suffix: Entity
    # for application.properties
    database.mongo.uri=mongodb://ezydata_mongo:ezydata_mongo@localhost:27017/ezydata-mongo
    database.mongo.database=ezydata-mongo
    database.mongo.collection.naming.case=UNDERSCORE
    database.mongo.collection.naming.ignored_suffix=Entity

4. Example

Let’s say we need create an http server application to manage a book store (Category, Author and Book), we need 6 apis

  • api/v1/author/add: Add an author
  • api/v1/category/add: Add a category
  • api/v1/book/add: Add a book
  • api/v1/books/{bookId}: Get a book by id
  • api/v1/books: Get a list of books
  • apiv1/books/expected-revenue:

4.1 Create entities class

To store Category, Author and Book to MongoDB, we need create 3 entities:

    import com.tvd12.ezydata.database.annotation.EzyCollection;
    import com.tvd12.ezyfox.annotation.EzyId;
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    @Getter
    @Setter
    @EzyCollection
    @AllArgsConstructor
    @NoArgsConstructor
    public class Category {
        @EzyId
        private long id;
        private String name;
    }
    @Getter
    @Setter
    @EzyCollection
    @AllArgsConstructor
    @NoArgsConstructor
    public class Author {
        @EzyId
        private long id;
        private String name;
    }
    @Getter
    @Setter
    @EzyCollection
    @AllArgsConstructor
    @NoArgsConstructor
    public class Book {
        @EzyId
        private Long id;
        private Long categoryId;
        private Long authorId;
        private String name;
        private BigDecimal price;
        private LocalDate releaseDate;
        private LocalDateTime releaseTime;
    }

4.2 Create repositories

We need create 3 repositories for 3 entities:

    import com.tvd12.ezydata.example.mongo.entity.Category;
    import com.tvd12.ezydata.mongodb.EzyMongoRepository;
    import com.tvd12.ezyfox.database.annotation.EzyRepository;
    @EzyRepository
    public interface CategoryRepository extends EzyMongoRepository {
        Category findByName(String name);
    }
    import com.tvd12.ezydata.example.mongo.entity.Author;
    import com.tvd12.ezydata.mongodb.EzyMongoRepository;
    import com.tvd12.ezyfox.database.annotation.EzyRepository;
    @EzyRepository
    public interface AuthorRepository extends EzyMongoRepository {
    }
    import java.util.List;
    import com.tvd12.ezydata.database.annotation.EzyQuery;
    import com.tvd12.ezydata.example.mongo.entity.Book;
    import com.tvd12.ezydata.example.mongo.result.SumBookPriceResult;
    import com.tvd12.ezydata.mongodb.EzyMongoRepository;
    import com.tvd12.ezyfox.database.annotation.EzyRepository;
    import com.tvd12.ezyfox.util.Next;
    @EzyRepository
    public interface BookRepository extends EzyMongoRepository {
        Book findByNameAndAuthorId(String name, Long authorId);
        @EzyQuery("{$orderby:{name:1}}")
        List findBooks(Next next);
        @EzyQuery("{$query:{name:{$lt:?0}}, $orderby:{name:1}}")
        List findByNameLt(String name, Next next);
        @EzyQuery("{$query:{name:{$gt:?0}}, $orderby:{name:1}}")
        List findByNameGt(String name, Next next);
        @EzyQuery("[{ $group: { _id : 'sum', sum : { $sum: {$toDecimal: '$price'}} } }]")
        SumBookPriceResult sumPrice();
    }

4.3 Save entities

Save a category, see more details

    Category category = new Category(
        maxIdRepository.incrementAndGet("category"),
        request.getCategoryName()
    );
    categoryRepository.save(category);

Save an author, see more details:

    Author author = new Author(
        maxIdRepository.incrementAndGet("author"),
        request.getAuthorName()
    );
    authorRepository.save(author);
    return author;

Save a book, see more details:

    val bookId = maxIdRepository.incrementAndGet("book");
    val book = requestToEntityConverter.toBookEntity(request, bookId);
    bookRepository.save(book);

4.4 Query data

Find a category by id, see more details:

    Category category = categoryRepository.findById(request.getCategoryId());

Find an author by id, see more details:

    Author author = authorRepository.findById(request.getAuthorId());

Find a book by name and author id, see more details:

    Book existedBook = bookRepository.findByNameAndAuthorId(
        request.getBookName(),
        request.getAuthorId()
    );

Get sum of all book prices, see BookRepository and BookController to get more details

    @EzyQuery("[{ $group: { _id : 'sum', sum : { $sum: {$toDecimal: '$price'}} } }]")
    SumBookPriceResult sumPrice();
    bookRepository.sumPrice().getSum()

4.5 Update data

You can update data with a function has update prefix like this:

    @EzyQuery("{$query: {_id : 4}, $update: {$set: {category: ?0}}}")
    void updateCategory(String category);

And you can delete data with a function has delete prefix like this:

    @EzyQuery("{_id : {$gt: ?0}}")
    void deleteByIdGt(int id);

Full source code available on Github.

5. Conclusion

With EzyMongo you will work with MongoDB lot easier and more native. With query string, you will don't need care about bson, criteria and you will reduce a lot of your source code.

Next

You can take a look EzyMongo configuration.