field access for lists of objects in a class via m

2019-06-13 19:37发布

问题:

I have some problems while implementing filters in mongodb using morphia POJO mapper.

In my class (for example SampleClass), when i try to access the fields of an @Entity class (in our case it's Person), I find the field access works fine, using dot notation for general fields like int, string, maps or direct embedded objects.

The issue is I could not understand how it works for the case of a "List of Objects" referenced in the Person class. (Assume here, a person can have many addresses, so this Person class has a field addresses which holds a list of Address objects)

@Entity
Class Person
{
    String name;
    int age;
    String type;
    private Map<String, String> personalInfo= new HashMap<String, String>();
    @Reference
    List<Address> addresses = new ArrayList<Address>;
}

@Entity
Class Address
{
    String streetName;
    int doorNo;
}

For example, I want to apply a filter on streetName of the Address object which is in the addresses List

public class SampleClass
{  
    private Datastore ds;
    Query<Node>              query;
    CriteriaContainer        container;

    // connections params etc....
    public List<Person> sampleMethod()
    {
        query = ds.find( Person.class ).field( "type" ).equal( "GOOD");                              

        container.add( query.criteria( "name" ).containsIgnoreCase("jo" ));   
        // general String field in the Person Class ---- OKAY, Work's Fine

        container.add( query.criteria( "personalInfo.telephone" ).containsIgnoreCase( "458" ) ); 
        // Map field in the Person Class, accessing telephone key value in the map --- OKAY, Work's Fine

        container.add( query.criteria( "addresses.streetname").containsIgnoreCase( "mainstreet" ) ); 
        // List of address object in the Person Class, name of the field is 'addresses'
        // ----NOT OKAY   ????????? -- Here is the problem it returns nothing, even though some value exists

        return readTopography( query.asList() );
    }
}

Am I doing something wrong while accessing the objects in a list?

回答1:

"addresses" field is a @Reference we cannot use "addresses.name" as a field in a criteria. It should be a criteria where addresses field is in a "List< Key< Address > >" :

    Query<Person> personQuery = ds.createQuery(Person.class);
    Query<Address> addressQuery = ds.createQuery(Address.class);
    addressQuery.criteria("streetName").containsIgnoreCase("mainstreet");
    container.add(personQuery.criteria("addresses").in(addressQuery.asKeyList()));

    System.out.println(personQuery.asList());

regards, sadish



回答2:

Your query you actually try would query an subdocument addresses with the field streetname. So you will only get documents which have addresses as a concrete address not a list of addresses. To match all Persons containing at least one address matching use $elemMatch http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray . But I'm not sure If Morphia is able to perform such queries, with your schema at all. Keep in mind that your actual Document isn't containing those addresses embedded, instead it contains only dbrefs http://www.mongodb.org/display/DOCS/Database+References . So if morphia isn't smart enough to convert your query it will not succeed, as mongoDB doesn't know DBRefs at all (as this is only some driver convention).

So for the case morphia doesn't offer this functionality you need to query different. At first you need to query your Addresses collection for addresses matching your condition. Collect those ObjectIds and use them with $elemMatch and $in in your Person Collection query, to filter out all persons not having such an address, along with your further filter options. You need to keep in mind that you don't have some relational System which does the joining for you.



回答3:

Its looks like tyop for me container.add( query.criteria( "addresses.streetname").containsIgnoreCase( "mainstreet" ) );.

I think streetname needs to be changed to streetName.

I have been using morphia for a year now. AFAIK, container.add( query.criteria( "addresses.streetName").containsIgnoreCase( "mainstreet" ) ); should work fine.