Charles Bryant Charles Bryant - 5 months ago 125
Java Question

Can CQEngine query an object inside another object

Does anyone know if CQEngine can query objects with in other objects? I would like to be able to query users, orders and products.

Can this be done with CQEngine or would I need to flatten the objects?

public class User {
public List<Orders> orders;
}

public class Orders {
public List<Products> products;
}

public class Products {
public String name;
}

Answer

Yes, you just need to define a CQEngine attribute which will return the values from the nested objects you want to search.

For example, this attribute will retrieve the names of each Product, which is contained in the Orders, which were placed by a particular User.

static final Attribute<User, String> PRODUCT_NAMES_ORDERED = new MultiValueAttribute<User, String>() {
    public Iterable<String> getValues(User user, QueryOptions queryOptions) {
        return user.orders.stream()
                .map(order -> order.products).flatMap(Collection::stream)
                .map(product -> product.name)::iterator;
    }
};

You could optionally add an index on this attribute, to accelerate queries on it.

Here's an example which sets up an IndexedCollection of Users, where each user has a number of Orders, and each order has a number of Products. The products are snacks you might find at a cinema. It searches the collection for users who ordered a "Snickers Bar".

package com.googlecode.cqengine.examples.nestedobjects;

import com.googlecode.cqengine.*;
import com.googlecode.cqengine.attribute.*;
import com.googlecode.cqengine.query.option.QueryOptions;
import java.util.*;
import static com.googlecode.cqengine.query.QueryFactory.*;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;

public class NestedObjectsExample {

    public static void main(String[] args) {
        Order order1 = new Order(asList(new Product("Diet Coke"), new Product("Snickers Bar")));
        Order order2 = new Order(singletonList(new Product("Sprite")));
        User user1 = new User(1, asList(order1, order2));

        Order order3 = new Order(asList(new Product("Sprite"), new Product("Popcorn")));
        User user2 = new User(2, singletonList(order3));

        Order order4 = new Order(singletonList(new Product("Snickers Bar")));
        User user3 = new User(3, singletonList(order4));

        IndexedCollection<User> users = new ConcurrentIndexedCollection<>();
        users.addAll(asList(user1, user2, user3));

        users.retrieve(equal(PRODUCT_NAMES_ORDERED, "Snickers Bar")).forEach(user -> System.out.println(user.userId));
        // ...prints 1, 3
    }

}

BTW I'm the author of CQEngine, and you can find the complete source for this example on the CQEngine site. (I have just added this as a new example!)

Comments