2

I am using objectbox for the database in my app. I have a one to many relation between my items and I want to sort my items based on that relation.

As an example I use these entities :

@Entity()
class ProductEntity {
  @Id()
  int id;
  int value;
  int type;
  final store = ToOne<StoreEntity>();

  ProductEntity({required this.value, required this.type, this.id = 0});
}

@Entity()
class StoreEntity {
  @Id()
  int id;
  final String name;
  @Backlink('store')
  final items = ToMany<ProductEntity>();

  StoreEntity({required this.name, this.id = 0});
}

What I want to achieve is to sort the stores based on the sum of values got through the products. And I cannot find a way to do that with objectbox queries.

To achieve that I used a map to sum values of products for each stores, but it doesn't seems very efficient. Here is an exemple :

void main() {
  runApp(const MainApp());
}

class MainApp extends StatefulWidget {
  const MainApp({super.key});

  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  Store? store;

  @override
  void initState() {
    super.initState();
    () async {
      // Create store
      final docsDir = await getApplicationDocumentsDirectory();
      store = await openStore(directory: docsDir.path);

      // Populate store with random values
      [...]
      setState(() {});
    }();
  }

  @override
  Widget build(BuildContext context) {
    List<StoreEntity> storesSelected;
    final valueMap = {};

    if (store == null) {
      storesSelected = [];
    } else {
      // Get stores with a condition on their name
      storesSelected = Box<StoreEntity>(
        store!,
      ).query(StoreEntity_.name.contains("Store")).build().find();
      // Get product with a condition on their type
      final productsSelected = Box<ProductEntity>(
        store!,
      ).query(ProductEntity_.type.equals(1)).build().find();
      // Use a map to compute total value for each stores
      for (var prod in productsSelected) {
        valueMap.update(
          prod.store.targetId,
          (value) => value + prod.value,
          ifAbsent: () => prod.value,
        );
      }
      // Keep only stores with products of the selected type
      storesSelected = storesSelected
          .where((x) => valueMap.keys.contains(x.id))
          .toList();
      // Order stores by value
      storesSelected.sort(
        (a, b) => (valueMap[b.id] ?? 0).compareTo(valueMap[a.id] ?? 0),
      );
    }

    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: SingleChildScrollView(
            child: Column(
              children: [
                // Display stores sorted by values of product type 1
                for (var s in storesSelected) Text("Store : ${s.name}"),
              ]))))
    );
  }
}

Is there a better way to do this type of sort efficiently directly with objectbox ?

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.