#
Read Operations
#
Find Operations
You can search entities in a repository using find()
method. There are several ways of using find()
method using a filter or find options or both. You can also search an entity using it's id.
#
Filters
Nitrite uses filters to find entities in a repository. A filter is a simple expression which evaluates to true
or false
. More information about filters can be found here.
#
Find All Entities
You can find all entities in a repository by calling find()
. It returns a Cursor
object.
Cursor<Product> cursor = productRepository.find();
#
Finding an Entity Using Id
You can find an entity using it's id by calling getById()
. It takes an id as input parameter. It returns an entity if the entity is found. Otherwise, it returns null
.
var product = await productRepository.getById(ProductId(1));
#
Finding an Entity Using a Filter
You can find an entity using a filter. It takes a Filter
object as input parameter. It returns a Cursor
object.
If there is an index on the field specified in the filter, this operation will use the index to find the entity. Otherwise, it will scan the entire repository to find the entity.
Cursor<Product> cursor = productRepository.find(filter: where('productName').eq('Apple iPhone 6'));
#
Finding an Entity Using a Filter and Options
You can find an entity using a filter and options. It takes a Filter
object as the first input parameter. It takes a FindOptions
object as the second input parameter. It returns a Cursor
object.
#
FindOptions
More information about FindOptions
can be found here.
#
Cursor
Cursor
represents a result set of a find operation. It provides methods to iterate over the result of a find operation and retrieve the entities. It also provides methods like projection, join etc. to get the desired result.
#
Iterating over Entities
The Cursor
extends Stream
of entities. So, you can iterate over the entities using await for loop.
Cursor<Product> cursor = productRepository.find();
await for (var product in cursor) {
// do something with product
}
A Cursor
is a stream of entities. It does not load all the entities in memory at once. It loads the entity in memory as needed. So, it is memory efficient.
#
Getting the Entities
You can get the entities from a Cursor
using toList()
method. It returns a Future<List<T>>
object.
Cursor<Product> cursor = productRepository.find();
var products = await cursor.toList();
#
Getting the First Entity
You can get the first entity from a Cursor
using first
getter. It returns a Future<T?>
object.
Cursor<Product> cursor = productRepository.find();
var product = await cursor.first;
#
Getting the Size of the Cursor
You can get the size of the cursor using length
getter. It returns a Future<int>
object.
Cursor<Product> cursor = productRepository.find();
var size = await cursor.length;
#
Projection
You can project a field or a set of fields from a Cursor
using project()
method. It takes another entity type as input parameter. It returns a Stream
of projected entities.
The projected entity must contain only the fields that needs to be projected.
Let's say you have an entity like this:
@Entity()
@Convertable()
class User {
String? firstName;
String? lastName;
Address? address;
User({this.firstName, this.lastName, this.address});
}
@Convertable()
class Address {
String? city;
String? state;
String? country;
Address({this.city, this.state, this.country});
}
Then you can project the lastName
and address.street
fields. Then you define a new entity like this:
@Entity()
@Convertable()
class UserProjection {
String? lastName;
StreetAddress? address;
UserProjection({this.lastName, this.address});
}
@Convertable()
class StreetAddress {
String? street;
StreetAddress({this.street});
}
And then you can project the cursor like this:
Cursor<User> cursor = userRepository.find(filter: where('firstName').eq('John'));
var projectedStream = cursor.project<UserProjection>();
#
Join
You can join two cursors using leftJoin()
method. It takes another cursor as the first input parameter. It takes a Lookup
as the second input parameter. The first type parameter is the type of the foreign entity. The second type parameter is the type of the joined entity. It returns a Stream
of joined entities.
The join operation is similar to SQL left outer join operation. It takes two cursors and a lookup object. The lookup object contains the join condition.
Let's say you have two entities like this:
@Entity()
@Convertable()
class User {
String? userId;
String? firstName;
String? lastName;
User({this.userId, this.firstName, this.lastName});
}
@Entity()
@Convertable()
class Order {
String? orderId;
String? userId;
String? productName;
Order({this.orderId, this.userId, this.productName});
}
And you want to join these two entities using userId
field. Then you can define a new entity like this:
@Entity()
@Convertable()
class UserOrder {
String? userId;
String? firstName;
String? lastName;
List<Order>? orders;
UserOrder({this.userId, this.firstName, this.lastName, this.orders});
}
And then you can join the cursors like this:
Cursor<User> userCursor = userRepository.find();
Cursor<Order> orderCursor = orderRepository.find();
var lookup = Lookup()
..localField = 'userId'
..foreignField = 'userId'
..alias = 'orders';
var joinedStream = userCursor.leftJoin<Order, UserOrder>(orderCursor, lookup);
#
FindPlan
You can get the FindPlan
of a cursor using findPlan
getter. It returns a future of FindPlan
object.
More information about FindPlan
can be found here.
Cursor<Product> cursor = productRepository.find(filter: where('productName').eq('Apple iPhone 6'));
var findPlan = await cursor.findPlan;