Miroslav B
Miroslav B

Reputation: 61

Spring boot MongoDb complex query

I have been learning myself MongoDB implementation in Spring Boot. However, I came into a problem with complex queries.

I cannot find any right solution for how to implement complex queries to MongoDB from Spring boot.

I am querying the database with MongoRepository interface implementation.

Let's say that I have three collections:

POJO classes are bellow

What do I want to achieve?

I want to make a query, which would be returned me a Person, whose Pet has a Toy (PetToy) with the name "Teddy".

I could not have found a way how to do it. Furthermore, is it the best practice to even use such complex queries, or is it better to write more of little ones in MongoDB?

POJOs:

@Document
@Data
@ToString
public class Person {

    @Id
    private String id;

    private String firstname;

    private String lastname;

    private int age;

    @DBRef
    private Pet pet;
}

@Document
@Data
@ToString
public class Pet {

    @Id
    private String id;

    private String name;

    private int age;

    @DBRef
    private List<PetToy> toys;
}

@Document
@Data
@ToString
public class PetToy {

    @Id
    private String id;

    private String name;
}

I have tried to use MongoRepositories; however, I was not able to make the complex query.

How can one write such a query to a MongoDB from Spring Boot?

Thank you very much in advance.

Upvotes: 3

Views: 5111

Answers (1)

earandap
earandap

Reputation: 1496

If you can use embedded attributes, the class model should be:

@Document
@Data
@Builder
public class Person {

    @Id
    private String id;

    private String firstName;

    private String lastName;

    private int age;

    private List<Pet> pets;
}
@Data
@Builder
public class Pet {

    private String name;

    private int age;

    private List<PetToy> toys;
}
@Data
@Builder
public class PetToy {

    private String name;
}

The repository with the method that achieves what you want:

public interface PersonRepository extends MongoRepository<Person, String> {
    List<Person> getByPetsToysName(String name);
}

The getByPetsToysName method basically navigate between Person's attributes Person->pets->toys->name. More info here.

An example

@Configuration
@EnableMongoRepositories
public class TestMongo implements CommandLineRunner {

  private final PersonRepository repository;

  public TestMongo(PersonRepository repository) {
    this.repository = repository;
  }

  @Override
  public void run(String... args) throws Exception {

    repository.save(Person.builder()
      .firstName("John")
      .lastName("Doe")
      .age(20)
      .pets(Stream.of(Pet.builder()
        .name("Ursa")
        .age(1)
        .toys(Stream.of(PetToy.builder()
          .name("Teddy")
          .build())
          .collect(Collectors.toList()))
        .build())
        .collect(Collectors.toList()))
      .build());

    repository.save(Person.builder()
      .firstName("Phillip")
      .lastName("Larson")
      .age(21)
      .pets(Stream.of(Pet.builder()
        .name("Bella")
        .age(5)
        .toys(Stream.of(PetToy.builder()
          .name("Lolo")
          .build())
          .collect(Collectors.toList()))
        .build())
        .collect(Collectors.toList()))
      .build());

    List<Person> persons = repository.getByPetsToysName("Teddy");
    System.out.println(persons.size());
    List<Person> persons1 = repository.getByPetsToysName("Lolo");
    System.out.println(persons1.size());
  }
}

Logs:

find using query: { "pets.toys.name" : "Teddy" } fields: Document{{}} for class: class Person in collection: person

If you want more complex queries you can to take a look at the Spring Data MongoDB docs.

Upvotes: 4

Related Questions