mongodb query with spring data for key-value
Asked Answered
P

4

5

I've been started a project with mongodb and spring boot and spring JPA data and I realised I cannot map my data model to entity and make a query on that easily, so I have two questions,

My data model is like that ( just for one Collection )

{
   name: "Name",
   lastName: "Last Name",
   attributes: {
      age: 25
      eye: {
         color: "RED",
         size: "BIG"
      }
   }
}

And my entity is

@Entity // or @Document
public class User{
   private String name;
   private String lastName;
   private Map<String, ?> attributes = new HashMap<>();

   // id or the setter getter are omitted
}
  1. Can I map attributes property in my mongodb collection like I did ( Map )
  2. How can I make query for finding the attributes?

    Can I do it like that? List<User> findAllByAttributesAge(Integer age);

Parimutuel answered 22/4, 2016 at 12:16 Comment(0)
J
3

Can I map attributes property in my mongodb collection like I did ( Map )

Yes, you can, and it may prove useful (though tricky) for a "dynamic" or "partly defined" schema.

If you know your schema in advance, I strongly recommend that it shows in your domain object. Take a look here.

How can I make query for finding the attributes?

If you don't use a dynamic schema, property traversal for nested properties is clearly explained in the Spring Data MongoDB Reference Documentation.

If you use dynamic schema, you'll most probably use MongoDB JSON based query methods.

Jeepers answered 22/4, 2016 at 16:10 Comment(2)
I have dynamic schema in some Entity but I don't want to use custom query like @Query annotation, I need to know is it possible to have query with convention? if yes how? @MarcTarinParimutuel
The documentation I pointed you to starts with "Property expressions can refer only to a direct property of the managed entity", so no, you can't just declare define a findBy query on a nested property if Spring doesn't know that it exists.Jeepers
S
9

Today I had a problem with Map query in Spring Mongodb, and since this question pops the first one in google I will provide another answer.

Since the other answer references to documentation, and that documentation does not have a lot of information, I am going to put an example of how good is the @Query annotation for dynamic schema:

@Query(value = "{'attributes.age' : ?0}")
List<User> findAllByAttributesAge(int age);

Also, you could query eye color, too:

@Query(value = "{'attributes.eye.color' : ?0}")
List<User> findAllByAttributesEyeColor(String color);

As the other answers documentation says, you could filter the result, and receive only the part of the document that you prefer:

// It will return the users with only name and last name
@Query(value = "{'attributes.age' : ?0}", fields = "{ name : 1, lastName : 1 }")
List<User> findAllByAttributesAge(int age);
Stratagem answered 30/1, 2018 at 20:32 Comment(0)
J
3

Can I map attributes property in my mongodb collection like I did ( Map )

Yes, you can, and it may prove useful (though tricky) for a "dynamic" or "partly defined" schema.

If you know your schema in advance, I strongly recommend that it shows in your domain object. Take a look here.

How can I make query for finding the attributes?

If you don't use a dynamic schema, property traversal for nested properties is clearly explained in the Spring Data MongoDB Reference Documentation.

If you use dynamic schema, you'll most probably use MongoDB JSON based query methods.

Jeepers answered 22/4, 2016 at 16:10 Comment(2)
I have dynamic schema in some Entity but I don't want to use custom query like @Query annotation, I need to know is it possible to have query with convention? if yes how? @MarcTarinParimutuel
The documentation I pointed you to starts with "Property expressions can refer only to a direct property of the managed entity", so no, you can't just declare define a findBy query on a nested property if Spring doesn't know that it exists.Jeepers
F
1

This gave me a tough time. The other answer pretty much helps with querying an object by the field value of an hashmap if you know the key for the field. But what if you don't know the key by which the object will be queried? I labored for hours trying to figure out what's wrong even after I followed Noki's very good explanation exactly. In my case, I have a Customer class that has a hashmap field to store account objects.

public class Customer {
    private String firstName;
    private String lastName;
    private Map<String, Account> customerAccounts = new HashMap<>();

    //Constructors, getters, setters...
}

A data Model collection looks something like this

   {
        firstName: "firstname",
        lastName: "lastname",
        customerAccounts: {
             "0123456789": {
                firstName: "firstName",
                lastName: "lastname",
                accoutNumber: "0123456789",
                accountType: "Savings"
            },
            "1012234494": {
                firstName: "firstname",
                lastName: "lastname",
                accoutNumber: "1012234494",
                accountType: "Current"
            }
        }
    }

So, I wanted to query the customer from the database by the accountNumber field of the account object inside customerAccounts. Since the keys for every account in each customerAcoounts object in any Customer is unique and dynamic, and no Customer collection has a similar accountNumber with another Customer collection, you'll need to write your query like this:

@Query(value = "{'customerAccount.?0.accountNumber' : ?0}"
Optional<Customer> findCustomerByCustomerAccount(String accountNumber);

The ?0 in 'customerAccount.?0.accountNumber' will take care of the dynamic value, find an object that its key matches exactly the argument coming in and finally check the accountNumber field for that account object.

Fluorine answered 5/11, 2022 at 11:59 Comment(0)
F
0

when using dynamic queries, The trick is to use the exact field name as per document and not as per your object model.

Ex:

public class Customer {
        @Field("first_name")
        private String firstName;
        @Field("last_name")
        private String lastName;
    
        @Field("customer_accounts")
        private Map<String, Account> customerAccounts = new HashMap<>();
    }

with dynamic queries like below wont work with field mapping.

@Query(value = "{'customer_accounts.?0.account_number' : ?0}"
Optional<Customer> findCustomerByCustomerAccount(String accountNumber);
Fishmonger answered 17/6 at 17:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.