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 ?