How to use .max() aggregate function in Isar database for Flutter? - flutter

I am learning how to use Isar database for my Flutter app. I am trying to get the maximum value of a column. The Isar documentation suggests that I can use the .max() aggregate function but does not give an example on how to actually use it in a query.
Below is the code I have. I would like someone to suggest what I put in place of <rest_of_query_here>. I tried putting it after .where(), .filter(), even after .findAll() but none is acceptable.
part 'client.g.dart';
#collection
class Client {
Id id = Isar.autoIncrement; // you can also use id = null to auto increment
#Index(type: IndexType.value)
String? clientId; // actually a number of the form '10001','10002',...
String? lastname;
String? firstname;
}
...
// We should use .max() somewhere in the query
Future<String> getMaxClientId() async {
final isar = await Isar.open([ClientSchema]);
final clientId = await isar.clients.<rest_of_query_here>;
return clientId == null ? '10000' : clientId;
}
...

According to this documentation, you need to run a property query to use the .max() operation. A property query isolates and returns a single property (or column if thinking in SQL terms) which you can then run aggregate operations on such as .max(), .min(), .sum(), .average().
For your example replace the <rest_of_query_here> line with the following:
final clientId = await isar.clients.where().clientIdProperty().max();

Related

flutter/firebase/dart: get data from firestore

How to get docs id from some matching condition?
I was able to get this to work:
Future getChat({required String userIdsArr}) async {
var docId = '';
await chat.where('User ids', isEqualTo: userIdsArr).get().then((value) {
value.docs.forEach((element) {
docId = element.id;
});
});
//print(docId);
return docId
}
this returns the correct record, however, I think this is a terrible way of quering the database because I have to fetch all the records everytime.
Is there a way to write this so that I get the doc Id of the matching condition?
Unfortunately, there is not a better way to accomplish this. When you use the where clause though, it won't fetch everything like you suspect, only records that contain the value you are querying for. I don't believe it's as expensive of a call as you might think.

MongoDB query for equal search with $regex

I have an entity
class Data {
string name;
string city;
string street;
string phone;
string email;
}
An api has been written to find Data by each param. This is search api so if a param is provided, it will be used if not then everything has to be queried for that param.
#Query("{'name': ?0,'city': ?1,'street': ?2, 'phone': ?3,'email': ?4}")
Page<IcePack> findDataSearchParams(String name,
String city,
String street,
String phone,
String email);
This only works when all the params are sent in the request. It wont work if any of the params are not sent because it will look for null value in the DB for that param.
I want to query everything for that param if it is not requested like the way it is done in SQL. I tired to use $regex with empty string when something is not sent but regex works like a like search but I want to do equal search
anyway to do this
Filtering out parts of the query depending on the input value is not directly supported. Nevertheless it can be done using #Query the $and and operator and a bit of SpEL.
interface Repo extends CrudRepository<IcePack,...> {
#Query("""
{ $and : [
?#{T(com.example.Repo.QueryUtil).ifPresent([0], 'name')},
?#{T(com.example.Repo.QueryUtil).ifPresent([1], 'city')},
...
]}
""")
Page<IcePack> findDataSearchParams(String name, String city, ...)
class QueryUtil {
public static Document ifPresent(Object value, String property) {
if(value == null) {
return new Document("$expr", true); // always true
}
return new Document(property, value); // eq match
}
}
// ...
}
Instead of addressing the target function via the T(...) Type expression writing an EvaluationContextExtension (see: json spel for details) allows to get rid of repeating the type name over and over again.

Bad state: field does not exist within the DocumentSnapshotPlatform. How to handle such errors?

I had a doubt like how to handle field does not exists situation like suppose i have released my app and in future updates i added a new field in doc then how can i handle if field does not exists.
For example, in shared preferences we use ??to handle data existence with the specified key value.
int val=prefs.getInt("myKey")??0;
as you can see that above code will set value of val to 0 if there's no value associated with the key- myKey. Similarly i would like to know is there any way of doing it for firestore document fields.
MyCode:-
class UserModel
{
final String? id;
final String? username;
final String? email;
UserModel({
this.id,
this.username,
this.email,
});
factory UserModel.fromDocument(DocumentSnapshot doc)
{
return UserModel(
id: doc['id'],
username: doc['username'],//suppose the username does not exist in the field then how can i assign the value "User" to the username?
email: doc['email'],
);
}
}
This is the problem when developing an app which use Firebase. If you add a field after there is already a data and if you try to get new field in dart, you are getting this error. I think the only solution is deleting all the old data which doesn't have new field. Or put this new field to all of your old data. It's kinda annoying. So make sure that you have to add all possible field in the beginning.
Unfortunately, you can't use like int val=prefs.getInt("myKey")??0; because it isn't even null.

Flutter Moor Database: Joining queries proper structure

I have just started to use Moor Database for Flutter. I am going to join my two tables to get some columns from both tables.
I have checked the example that is given in docs as follow:
// we define a data class to contain both a todo entry and the associated category
class EntryWithCategory {
EntryWithCategory(this.entry, this.category);
final TodoEntry entry;
final Category category;
}
// in the database class, we can then load the category for each entry
Stream<List<EntryWithCategory>> entriesWithCategory() {
final query = select(todos).join([
leftOuterJoin(categories, categories.id.equalsExp(todos.category)),
]);
// see next section on how to parse the result
}
I am not able to understand that where to put this class. If I am creating a new class then it's giving me an error that the select keyword is not found. Also tried to import related to moor but not working.
Where I can write join queries and make this class?
Moor basically says to get the results and build the class manually. That class has no relationship with the database, so you can put it wherever you want. It is just the suggested way of doing it.
So, the select statement returns an object that you can iterate over the resulting rows, as an SQL response. And with that results build the classes that will be returned.
Look at the next example of the docs:
return query.watch().map((rows) {
return rows.map((row) {
return EntryWithCategory(
row.readTable(todos),
row.readTableOrNull(categories),
);
}).toList();
});
Because is a stream, calls watch(),and then map().
This first map returns the result of the query, properly name rows, every time one of the rows changes in the database, it will emit all the rows again.
The second map inside the first is for turning every row into a EntryWithCategory object. That way the whole function returns a list of those object updated with every change.
You can create other model for several tables.
Try this variant.
import 'package:drift/drift.dart';
part 'car_dao.g.dart';
#DriftAccessor(tables: [Cars, Bikes])
class CarDao extends DatabaseAccessor<AppDatabase> with _$CarDaoMixin {
final AppDatabase db;
CarDao(this.db) : super(db);
Future<List<CarWithBikeModel>> getCarsWithBikes() async {
final carList = await (select(cars).get();
final bikeList = await (select(bikes).get();
return CarWithBikeModel(
cars: carList,
bikes: bikeList);
}
}

Using the Dart/Flutter Postgres Package to store dates and null dates needs two separate commands

I am using the Postgres Package (On the pub.dev site) to UPDATE records in a very simple database. It has two fields: a Text field prime key named number, and a Date field named date_of_birth.
If the date_of_birth is a valid DateTime string then all is well (as can be seen from the code below). But if date_of_birth is unknown (so I set to null) the UPDATE fails:
import 'package:postgres/postgres.dart';
void main() async {
final conn = PostgreSQLConnection(
'localhost',
XXXXX,
'XXXXX',
username: 'XXXXX',
password: 'XXXXX',
);
await conn.open();
DateTime dob = DateTime.now();
var results;
results = await conn.query('''
UPDATE account_details
SET date_of_birth = '$dob'
WHERE number = '123123'
''');
await conn.close();
}
If I set:
dob = null;
The program fails with the error:
Unhandled exception:
PostgreSQLSeverity.error 22007: invalid input syntax for type date: "null"
So I need to include a check on the dob field and the program now looks like this:
DateTime dob = DateTime.now();
dob = null;
var results;
if (dob == null) {
results = await conn.query('''
UPDATE account_details
SET date_of_birth = null
WHERE number = '123123'
''');
} else {
results = await conn.query('''
UPDATE account_details
SET date_of_birth = '$dob'
WHERE number = '123123'
''');
}
That works fine for my simple database, but in my real App. I have a number of date fields in one table. So I have to do a check for each possible combination of those date values - writing a code block for each!
Can anyone tell me how I can UPDATE both null and a valid date using a single statement please?
You are quoting the query parameters yourself. NEVER do this. In addition to the sort of problem you have just seen it also leaves you open to a trivial SQL injection attack.
The library you are using will have some way of putting placeholders into the query text and passing variables when executing the query. Use that.