Isar Plus

Sorgular

Isar Plus ile güçlü ve verimli sorgular oluşturun

Sorgular

Sorgulama, belirli koşulları sağlayan kayıtları bulma yöntemidir. Güçlü sorgular oluşturmayı ve indekslerle nasıl optimize edeceğinizi öğrenin.

Sorgular Dart'ta değil veritabanında çalışır; bu yüzden inanılmaz derecede hızlıdır!

Genel Bakış

Kayıtlarınızı filtrelemek için iki farklı yöntem vardır. Her ikisi de .where() ile başlar ancak arka planda farklı çalışır:

  1. Filtreler - Kullanımı kolaydır, herhangi bir özellikte çalışır (tüm kayıtları tarar)
  2. Where cümleleri - Daha güçlüdür, indeks gerektirir (son derece hızlıdır)

API birleşiktir: her zaman .where() ile başlarsınız. İndeksli bir özellik üzerinde koşul kullanırsanız, otomatik olarak hızlı bir "Where cümlesi" olur. İndeksli olmayan bir özellik kullanırsanız, bir "Filtre" olur.

Filtreler

Filtreler koleksiyondaki her nesne için bir ifadeyi değerlendirir. İfade true dönerse nesne sonuçlara eklenir.

Örnek Model

@collection
class Shoe {
  Id? id;

  int? size;

  late String model;

  late bool isUnisex;
}

Sorgu Koşulları

// 46 numara ayakkabılar
final result = await isar.shoes.where()
  .sizeEqualTo(46)
  .findAll();
// 40 numaradan küçük ayakkabılar
final result = await isar.shoes.where()
  .sizeLessThan(40)
  .findAll(); // -> [39, null]

// Sınırı dahil et
final result2 = await isar.shoes.where()
  .sizeLessThan(40, include: true)
  .findAll(); // -> [39, null, 40]
// 39 ile 46 arası ayakkabılar
final result = await isar.shoes.where()
  .sizeBetween(39, 46)
  .findAll();

// Alt sınırı hariç tut
final result2 = await isar.shoes.where()
  .sizeBetween(39, 46, includeLower: false)
  .findAll(); // -> [40, 46]
// Boyutu null olan ayakkabılar
final nullSizes = await isar.shoes.where()
  .sizeIsNull()
  .findAll();

// Boyutu null olmayan ayakkabılar
final withSizes = await isar.shoes.where()
  .sizeIsNotNull()
  .findAll();

Kullanılabilir Koşullar

KoşulAçıklama
.equalTo(value)Belirtilen değere eşit olanları getirir
.between(lower, upper)Alt ve üst sınır arasındaki değerleri getirir
.greaterThan(bound)Sınırdan büyük değerleri getirir
.lessThan(bound)Sınırdan küçük değerleri getirir
.isNull()Null değerleri eşleştirir
.isNotNull()Null olmayanları eşleştirir
.length()Liste/string uzunluğuna göre sorgular

Mantıksal Operatörler

Birden fazla koşulu mantıksal operatörlerle birleştirin:

// AND operatörü (örtük)
final result = await isar.shoes.where()
  .sizeEqualTo(46)
  .and() // Opsiyonel
  .isUnisexEqualTo(true)
  .findAll();
// size == 46 && isUnisex == true
final result = await isar.shoes.where()
  .sizeEqualTo(46)
  .and()
  .isUnisexEqualTo(true)
  .findAll();
final result = await isar.shoes.where()
  .sizeEqualTo(46)
  .or()
  .sizeEqualTo(40)
  .findAll();
final result = await isar.shoes.where()
  .not().sizeEqualTo(46)
  .and()
  .not().isUnisexEqualTo(true)
  .findAll();
// size != 46 && isUnisex != true
final result = await isar.shoes.where()
  .sizeBetween(43, 46)
  .and()
  .group((q) => q
    .modelContains('Nike')
    .or()
    .isUnisexEqualTo(false)
  )
  .findAll();
// size >= 43 && size <= 46 && (model.contains('Nike') || isUnisex == false)

String Koşulları

String'ler için ek güçlü koşullar vardır:

@collection
class Product {
  Id? id;
  late String name;
}
final products = await isar.products.where()
  .nameStartsWith('iPhone')
  .findAll();

// Büyük/küçük harf duyarsız
final products2 = await isar.products.where()
  .nameStartsWith('iphone', caseSensitive: false)
  .findAll();
final products = await isar.products.where()
  .nameContains('Pro')
  .findAll();
final products = await isar.products.where()
  .nameEndsWith('Max')
  .findAll();
// Wildcard desenleri: * (0+ karakter), ? (tek karakter)
final products = await isar.products.where()
  .nameMatches('iPhone *Pro')
  .findAll();
// "iPhone 14 Pro", "iPhone 15 Pro" vb.

Tüm string işlemlerinde varsayılanı true olan isteğe bağlı caseSensitive parametresi bulunur.

Sorgu Değiştiricileri

Koşullara göre dinamik sorgular oluşturun:

Opsiyonel Sorgular

Future<List<Shoe>> findShoes(int? sizeFilter) {
  return isar.shoes.where()
    .optional(
      sizeFilter != null,
      (q) => q.sizeEqualTo(sizeFilter!),
    )
    .findAll();
}

AnyOf Modifiyeri

// 38, 40 veya 42 numara ayakkabılar
final shoes = await isar.shoes.where()
  .anyOf(
    [38, 40, 42],
    (q, int size) => q.sizeEqualTo(size)
  )
  .findAll();

// Eşdeğer:
final shoes2 = await isar.shoes.where()
  .sizeEqualTo(38)
  .or()
  .sizeEqualTo(40)
  .or()
  .sizeEqualTo(42)
  .findAll();

AllOf Modifiyeri

final shoes = await isar.shoes.where()
  .allOf(
    ['Nike', 'Adidas'],
    (q, brand) => q.modelContains(brand)
  )

Gelişmiş: Özel Sorgular (Custom Queries)

Sorguları çalışma zamanında dinamik olarak oluşturmanız gereken karmaşık senaryolar için buildQuery kullanabilirsiniz. Bu, özel sorgu dilleri veya dinamik filtreleme arayüzleri oluşturmak için yararlıdır.

// Filter nesnesini manuel oluşturma
final filter = AndGroup([
  EqualCondition(property: 1, value: 46), // özellik 1: 'size'
  GreaterCondition(property: 2, value: 100), // özellik 2: 'price'
]);

final query = isar.shoes.buildQuery(
  filter: filter,
  sortBy: [
    SortProperty(property: 1, sort: Sort.desc), // boyuta göre azalan sırala
  ],
);

final results = await query.findAllAsync();

buildQuery kullanmak, şemanızın özellik indeksleri (property index) hakkında derin bilgi gerektirir. Mümkün olduğunda üretilen .where() API'sini kullanmanız önerilir.

Liste Sorguları

Liste özelliklerine göre sorgulama:

@collection
class Tweet {
  Id? id;
  String? text;
  List<String> hashtags = [];
}
// Çok hashtag'li tweetler
final tweets = await isar.tweets.where()
  .hashtagsLengthGreaterThan(5)
  .findAll();
// Belirli hashtag'i içeren tweetler
final flutterTweets = await isar.tweets.where()
  .hashtagsElementEqualTo('flutter')
  .findAll();
// tweets.where((t) => t.hashtags.contains('flutter'))
// Hashtag'siz tweetler
final tweets = await isar.tweets.where()
  .hashtagsIsEmpty()
  .findAll();

Gömülü Nesneler

İç içe gömülü nesneleri verimli sorgulayın:

@collection
class Car {
  Id? id;
  Brand? brand;
}

@embedded
class Brand {
  String? name;
  String? country;
}
// Almanya'dan BMW'ler
final germanCars = await isar.cars.where()
  .brand((q) => q
    .nameEqualTo('BMW')
    .and()
    .countryEqualTo('Germany')
  )
  .findAll();

Daha iyi performans için iç içe sorguları her zaman gruplayın!

Linkli nesnelere göre sorgu:

@collection
class Teacher {
  Id? id;
  late String subject;
}

@collection
class Student {
  Id? id;
  late String name;
  final teachers = IsarLinks<Teacher>();
}
// Matematik veya İngilizce öğretmeni olan öğrenciler
final students = await isar.students.where()
  .teachers((q) => q
    .subjectEqualTo('Math')
    .or()
    .subjectEqualTo('English')
  )
  .findAll();

// Link sayısına göre sorgu
final studentsWithManyTeachers = await isar.students.where()
  .teachersLengthGreaterThan(3)
  .findAll();

Link sorguları maliyetli olabilir. Daha iyi performans için gömülü nesneleri düşünün.

Where Cümleleri

Where cümleleri indeksleri kullanarak ultra hızlı sorgular sağlar:

@collection
class Product {
  Id? id;
  
  @Index()
  late String name;
  
  @Index()
  late int price;
}
// Hızlı sorgu için indeks kullanın
final products = await isar.products
  .where()
  .nameEqualTo('iPhone')
  .findAll();

// Filtrelerle birleştirin
final expensiveIPhones = await isar.products
  .where()
  .nameEqualTo('iPhone')
  .where()
  .priceGreaterThan(1000)
  .findAll();

Where cümleleri filtrelere göre çok daha hızlıdır ancak indeks gerektirir.

Sorgu Operasyonları

Find Operasyonları

final allShoes = await isar.shoes
  .where()
  .sizeGreaterThan(40)
  .findAll();
final firstShoe = await isar.shoes
  .where()
  .sizeEqualTo(46)
  .findFirst();
final count = await isar.shoes
  .where()
  .sizeGreaterThan(40)
  .count();
final isEmpty = await isar.shoes
  .where()
  .sizeEqualTo(99)
  .isEmpty();

Silme Operasyonları

// Koşulu sağlayan nesneleri sil
await isar.writeAsync((isar) async {
  final count = isar.shoes
    .where()
    .sizeLessThan(35)
    .deleteAll();
  print('Silinen ayakkabı: $count');
});

Sıralama

Sonuçları herhangi bir özelliğe göre sırala:

// Artan
final sorted = await isar.shoes
  .where()
  .sortBySize()
  .findAll();

// Azalan
final sortedDesc = await isar.shoes
  .where()
  .sortBySizeDesc()
  .findAll();

// Çoklu sıralama
final multiSort = await isar.shoes
  .where()
  .sortBySize()
  .thenByModel()
  .findAll();

İndeks olmadan sıralama büyük veri setlerinde pahalıdır. Mümkün olduğunda indeksli where cümleleriyle sıralayın.

Limit & Offset

// İlk 10 sonuç
final first10 = await isar.shoes
  .where()
  .limit(10)
  .findAll();

// İlk 20'yi atla, sonraki 10'u getir
final paginated = await isar.shoes
  .where()
  .offset(20)
  .limit(10)
  .findAll();

Distinct

// Benzersiz numaraları getir
final uniqueSizes = await isar.shoes
  .where()
  .distinctBySize()
  .findAll();

En İyi Uygulamalar

  1. İndeksli Where Cümleleri Kullanın

    // ✅ Hızlı - indeks kullanır (price indekslidir)
    await isar.products.where().priceEqualTo(500).findAllAsync();
    
    // ❌ Yavaş - tüm kayıtları tarar (name indeksli değildir)
    await isar.products.where().nameEqualTo('iPhone').findAllAsync();
  2. Where ve Filtreyi Birleştirin

    // ✅ Optimal - indeks + filtre
    await isar.products
      .where()
      .nameEqualTo('iPhone')
      .where()
      .priceGreaterThan(500)
      .findAll();
  3. İç İçe Sorguları Gruplayın

    // ✅ Verimli
    .brand((q) => q.nameEqualTo('BMW').and().countryEqualTo('Germany'))
    
    // ❌ Verimsiz
    .brand((q) => q.nameEqualTo('BMW'))
    .and()
    .brand((q) => q.countryEqualTo('Germany'))

Sonraki Adımlar

Son Güncelleme