0

こんにちは、Jongo を使用して、$unwindオペレーターを使用して個人のコレクションからアドレスのリストを取得する際に問題が発生しています。

ご覧のとおり、Person クラスを次のように定義しました。

public class Person {
    @Id
    private long personId;
    private String name;
    private int age;
    private List<Address> addresses;
//getters and setters

Address クラスは次のように定義されます。

public class Address {
    private String houseNumber;
    private String road;
    private String town;
    private String postalCode;
//gettes and setters

クエリは非常に単純です。

public List<Address> getAddressByPersonId(long id) {
    List<Address> list = persons.aggregate("{$project:{addresses:1}}")
                                    .and("{$match:{_id:#}}",id)
                                    .and("{$unwind: '$addresses'}")
                                    .as(Address.class);
    return list;
}

私のコレクション:

> db.persons.find()
{ "name" : "Bob", "age" : 34, "addresses" : [   {       "houseNumber" : "12",
"road" : "High Street",         "town" : "Small Town",  "postalCode" : "BC2 3DE"
 },     {       "houseNumber" : "12",   "road" : "High Street",         "town" :
 "Small Town",  "postalCode" : "BC2 3DE" } ], "_id" : NumberLong(1) }
>

これにもJUnitテストがあります:

    @Before
    public void setUp(){
        service = new PersonServiceImpl();

        //store a person into the database (manually) before the tests
        MongoCollection persons = Database.getInstance().getCollection(CollectionNames.PERSONS);
        //create a new person
        Person p = new Person();
        p.setPersonId(1L);
        p.setName("Bob");
        p.setAge(34);
        //create two addresses for this person
        Address a = new Address();


        a.setHouseNumber("33");
        a.setRoad("Fake Road");
        a.setPostalCode("AB1 2CD");
        a.setTown("Big Town");
        p.addAddress(a);

        a.setHouseNumber("12");
        a.setRoad("High Street");
        a.setPostalCode("BC2 3DE");
        a.setTown("Small Town");
        p.addAddress(a);

        persons.save(p);
    }

    @After
    public void tearDown(){
        service = null;
    }

    @Test
    public void getAddressesByPersonIdTest(){

        List<Address> list = service.getAddressByPersonId(1L);
        for (Address item : list){
            item.print();
        }

        Assert.assertTrue(list.size() > 0);
    }
}

どの出力

### Address: null null, null, null 
### Address: null null, null, null 

何が問題なのかよくわかりません。どうやらテストは失敗しません(つまりlist.size()、0 より大きくなりますが、null を出力します)。print()メソッドがテストされ、機能します。

ボブの 2 つのアドレスを取得したいのですが、クエリは null オブジェクトを返します。何か不足していますか?$unwindを別の方法で使用する必要がありますか? 提案してください

4

2 に答える 2

1

Jongo を使用して問題を解決するために、いくつかの追加情報を追加したいと思います。

Addressesオブジェクトの不必要なインスタンス化を避けて、Mongo の結果をオブジェクトのリストに直接マップしたかったのPersonです。クラスPersonに次の追加フィールドがあるとします。

...
List<Address> addresses; 
List<Purchases> purchases; 
List<Payments> creditcards;
List<Product> watchlist;
//etc
...

ただし、取得する必要があるのは'addresses'. したがって、最初のアプローチは次のようになります。

解決策 1)

public List<Address> getAddressByPersonId(long id) {
        List<Address> list = persons.aggregate("{$match: {_id: #}}", id)
                .and("{$project: {addresses: 1, _id: 0}}")
                .and("{$unwind: '$addresses'}")
                .and("{$project: {houseNumber:'$addresses.houseNumber', road:'$addresses.road', town:'$addresses.town', postalCode:'$addresses.postalCode'}}")
                .as(Address.class);
        return list;
    }

長所:のリストのみが必要でAddresses、メモリ割り当てが少なくて済みます。短所:$projectクラスのすべてのフィールドが必要です。Addressそれ以外の場合、これは Jongo (null) でマップされません。@Asya Kamsky指摘したように、これはスケーラブルなソリューションではありません。

解決策 2)

public List<Address> getAddressByPersonId(long id) {
        List<Person> list = persons.aggregate("{$match:{_id:#}}",id).and("{$project: {addresses: 1, _id: 0}}")
                .as(Person.class);

        return list.get(0).getAddresses();
    }

長所:adddress必要なリストのフィールドを指定する必要はありません。したがって、フィールドを追加したい場合のスケーラブルなソリューションです。短所:オブジェクト全体を割り当てる必要があるためPerson、同様のシナリオで複雑なオブジェクトやレコードのロードを処理する場合、かなりのオーバーヘッドが発生する可能性があります。

他に機能する (Jongo) ソリューションがある場合は、共有してください。

于 2013-11-18T19:43:07.553 に答える