Nitrite is a pure Dart database. It does not depend on any native library. So it can be used in any platform where Dart is supported. It is a server-less embedded database ideal for desktop, mobile, or web applications. It is written in pure Dart and runs in Flutter, Dart VM, and the browser.
-
To get started with Nitrite database, you need to add the dependency to your pubspec.yaml file.
#Add dependency
-
Add Nitrite dependency to your project:
+
To use Nitrite in you project, add the following package to your package:
-
dependencies:
- nitrite: ^[latest version]
+
dart pub add nitrite
-
The latest released version of Nitrite can be found here.
-
To add the nitrite code generator to your project, add the following to your pubspec.yaml file:
+
To add the nitrite code generator to your project:
The migration is executed only once for a specific schema version. If you want to execute the migration again, you need to change the schema version of the database.
+
The migration is executed only once for a specific schema version.ni If you want to execute the migration again, you need to change the schema version of the database.
diff --git a/resources/js/config.js b/resources/js/config.js
index 668f091..3c1462d 100644
--- a/resources/js/config.js
+++ b/resources/js/config.js
@@ -1 +1 @@
-var __DOCS_CONFIG__ = {"id":"azVHQKu0Wzix5OiRqx+Ocp238Yia8ggOXT2","key":"hAoi2Pq/u/XDOMsd0FOPAzTUa3aDJHjAcD9dorkrmhQ.cbCxIMOCYgpsDDsMz1kVAotzIvfSB2wzEuhGH8BYyhKu45bUe6kt6nhDaz64acXm2+XBLCUrAZZWV4Ms4ZnqIA.14","base":"/","host":"nitrite.dizitart.com","version":"1.0.0","useRelativePaths":true,"documentName":"index.html","appendDocumentName":true,"trailingSlash":true,"preloadSearch":true,"cacheBustingToken":"3.5.0.758015411225","cacheBustingStrategy":"query","sidebarFilterPlaceholder":"Filter","toolbarFilterPlaceholder":"Filter","showSidebarFilter":true,"filterNotFoundMsg":"No member names found containing the query \"{query}\"","maxHistoryItems":15,"homeIcon":"","access":[{"value":"public","label":"Public"},{"value":"protected","label":"Protected"}],"toolbarLinks":[{"id":"fields","label":"Fields"},{"id":"properties","label":"Properties"},{"id":"methods","label":"Methods"},{"id":"events","label":"Events"}],"sidebar":[{"n":"/","l":"Welcome","s":""},{"n":"java-sdk","l":"Java Guides","c":false,"i":[{"n":"getting-started","l":"Getting Started","s":""},{"n":"database","l":"Nitrite Database","s":""},{"n":"document","l":"Document","s":""},{"n":"collection","l":"Nitrite Collection","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"repository","l":"Object Repository","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"entity","l":"Entity","s":""},{"n":"mapper","l":"NitriteMapper","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"filter","l":"Filters","s":""},{"n":"transaction","l":"Transaction","s":""},{"n":"migration","l":"Schema Migration","s":""},{"n":"modules","l":"Nitrite Modules","c":false,"i":[{"n":"module-system","l":"Module System","s":""},{"n":"store-modules","l":"Storage Modules","i":[{"n":"mvstore","l":"MVStore Modules","s":""},{"n":"rocksdb","l":"RocksDB Module","s":""},{"n":"custom","l":"Custom Storage Modules","s":""}],"s":""},{"n":"spatial","l":"Spatial Module","s":""},{"n":"jackson","l":"Jackson Mapper Module","s":""}],"s":""},{"n":"support","l":"Support","c":false,"i":[{"n":"installation","l":"Usage","s":""},{"n":"exchange","l":"Import/Export","s":""},{"n":"encryption","l":"Encryption","s":""}],"s":""}],"s":""},{"n":"kotlin-sdk","l":"Kotlin Guides","c":false,"i":[{"n":"getting-started","l":"Getting Started","s":""},{"n":"database","l":"Nitrite Database","s":""},{"n":"document","l":"Document","s":""},{"n":"collection","l":"Nitrite Collection","s":""},{"n":"repository","l":"Object Repository","s":""},{"n":"filter","l":"Filters","s":""},{"n":"transaction","l":"Transaction","s":""},{"n":"kno2","l":"Potassium Nitrite Module","s":""}],"s":""},{"n":"flutter-sdk","l":"Flutter Guides","c":false,"i":[{"n":"getting-started","l":"Getting Started","s":""},{"n":"database","l":"Database","s":""},{"n":"document","l":"Document","s":""},{"n":"collection","l":"Nitrite Collection","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"repository","l":"Object Repository","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"codegen","l":"Code Generator","s":""},{"n":"entity","l":"Entity","s":""},{"n":"mapper","l":"NitriteMapper","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"filter","l":"Filters","s":""},{"n":"transaction","l":"Transaction","s":""},{"n":"migration","l":"Schema Migration","s":""},{"n":"modules","l":"Nitrite Modules","c":false,"i":[{"n":"module-system","l":"Module System","s":""},{"n":"store-modules","l":"Storage Modules","i":[{"n":"hive","l":"Hive Modules","s":""},{"n":"custom","l":"Custom Storage Modules","s":""}],"s":""},{"n":"spatial","l":"Spatial Module","s":""}],"s":""},{"n":"support","l":"Support","c":false,"i":[{"n":"installation","l":"Usage","s":""},{"n":"exchange","l":"Import/Export","s":""},{"n":"encryption","l":"Encryption","s":""}],"s":""}],"s":""},{"n":"examples","l":"Examples","c":false,"i":[{"n":"java","l":"Java Examples","s":""},{"n":"flutter","l":"Flutter Examples","s":""}],"s":""},{"n":"showcase","l":"Showcase","s":""},{"n":"faq","l":"FAQ","s":""}],"search":{"mode":0,"minChars":2,"maxResults":20,"placeholder":"Search","hotkeys":["/"],"noResultsFoundMsg":"No Results","recognizeLanguages":true,"languages":[0],"preload":true},"resources":{"History_Title_Label":"History","History_ClearLink_Label":"Clear","History_NoHistory_Label":"No history items","API_AccessFilter_Label":"Access","API_ParameterSection_Label":"PARAMETERS","API_SignatureSection_Label":"SIGNATURE","API_CopyHint_Label":"Copy","API_CopyNameHint_Label":"Copy name","API_CopyLinkHint_Label":"Copy link","API_CopiedAckHint_Label":"Copied!","API_MoreOverloads_Label":"more","API_MoreDropdownItems_Label":"More","API_OptionalParameter_Label":"optional","API_DefaultParameterValue_Label":"Default value","API_InheritedFilter_Label":"Inherited","Search_Input_Placeholder":"Search","Toc_Contents_Label":"Contents","Toc_RelatedClasses_Label":"Related Classes","History_JustNowTime_Label":"just now","History_AgoTime_Label":"ago","History_YearTime_Label":"y","History_MonthTime_Label":"mo","History_DayTime_Label":"d","History_HourTime_Label":"h","History_MinuteTime_Label":"m","History_SecondTime_Label":"s"}};
+var __DOCS_CONFIG__ = {"id":"8NQa68V9qgKzCTl49sRbvFZOicKu238yJhZ","key":"S7fF8CRBR6H5fBogKak4bx3H9IfDT4Xg14XRXE9QUuo.iztOUtmg92kFO+LJHNQmfr9MWGeNC56FOe2UBP0eNz1oRd44ZdeDnjr6SQQwPLLKguZYFWESP23/fIXqX36Raw.41","base":"/","host":"nitrite.dizitart.com","version":"1.0.0","useRelativePaths":true,"documentName":"index.html","appendDocumentName":true,"trailingSlash":true,"preloadSearch":true,"cacheBustingToken":"3.5.0.758260768886","cacheBustingStrategy":"query","sidebarFilterPlaceholder":"Filter","toolbarFilterPlaceholder":"Filter","showSidebarFilter":true,"filterNotFoundMsg":"No member names found containing the query \"{query}\"","maxHistoryItems":15,"homeIcon":"","access":[{"value":"public","label":"Public"},{"value":"protected","label":"Protected"}],"toolbarLinks":[{"id":"fields","label":"Fields"},{"id":"properties","label":"Properties"},{"id":"methods","label":"Methods"},{"id":"events","label":"Events"}],"sidebar":[{"n":"/","l":"Welcome","s":""},{"n":"java-sdk","l":"Java Guides","c":false,"i":[{"n":"getting-started","l":"Getting Started","s":""},{"n":"database","l":"Nitrite Database","s":""},{"n":"document","l":"Document","s":""},{"n":"collection","l":"Nitrite Collection","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"repository","l":"Object Repository","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"entity","l":"Entity","s":""},{"n":"mapper","l":"NitriteMapper","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"filter","l":"Filters","s":""},{"n":"transaction","l":"Transaction","s":""},{"n":"migration","l":"Schema Migration","s":""},{"n":"modules","l":"Nitrite Modules","c":false,"i":[{"n":"module-system","l":"Module System","s":""},{"n":"store-modules","l":"Storage Modules","i":[{"n":"mvstore","l":"MVStore Modules","s":""},{"n":"rocksdb","l":"RocksDB Module","s":""},{"n":"custom","l":"Custom Storage Modules","s":""}],"s":""},{"n":"spatial","l":"Spatial Module","s":""},{"n":"jackson","l":"Jackson Mapper Module","s":""}],"s":""},{"n":"support","l":"Support","c":false,"i":[{"n":"installation","l":"Usage","s":""},{"n":"exchange","l":"Import/Export","s":""},{"n":"encryption","l":"Encryption","s":""}],"s":""}],"s":""},{"n":"kotlin-sdk","l":"Kotlin Guides","c":false,"i":[{"n":"getting-started","l":"Getting Started","s":""},{"n":"database","l":"Nitrite Database","s":""},{"n":"document","l":"Document","s":""},{"n":"collection","l":"Nitrite Collection","s":""},{"n":"repository","l":"Object Repository","s":""},{"n":"filter","l":"Filters","s":""},{"n":"transaction","l":"Transaction","s":""},{"n":"kno2","l":"Potassium Nitrite Module","s":""}],"s":""},{"n":"flutter-sdk","l":"Flutter Guides","c":false,"i":[{"n":"getting-started","l":"Getting Started","s":""},{"n":"database","l":"Database","s":""},{"n":"document","l":"Document","s":""},{"n":"collection","l":"Nitrite Collection","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"repository","l":"Object Repository","c":false,"i":[{"n":"intro","l":"Introduction","s":""},{"n":"codegen","l":"Code Generator","s":""},{"n":"entity","l":"Entity","s":""},{"n":"mapper","l":"NitriteMapper","s":""},{"n":"write","l":"Write Operations","s":""},{"n":"read","l":"Read Operations","s":""},{"n":"indexing","l":"Indexing","s":""},{"n":"other","l":"Other Operations","s":""}],"s":""},{"n":"filter","l":"Filters","s":""},{"n":"transaction","l":"Transaction","s":""},{"n":"migration","l":"Schema Migration","s":""},{"n":"modules","l":"Nitrite Modules","c":false,"i":[{"n":"module-system","l":"Module System","s":""},{"n":"store-modules","l":"Storage Modules","i":[{"n":"hive","l":"Hive Modules","s":""},{"n":"custom","l":"Custom Storage Modules","s":""}],"s":""},{"n":"spatial","l":"Spatial Module","s":""}],"s":""},{"n":"support","l":"Support","c":false,"i":[{"n":"installation","l":"Usage","s":""},{"n":"exchange","l":"Import/Export","s":""},{"n":"encryption","l":"Encryption","s":""}],"s":""}],"s":""},{"n":"examples","l":"Examples","c":false,"i":[{"n":"java","l":"Java Examples","s":""},{"n":"flutter","l":"Flutter Examples","s":""}],"s":""},{"n":"showcase","l":"Showcase","s":""},{"n":"faq","l":"FAQ","s":""}],"search":{"mode":0,"minChars":2,"maxResults":20,"placeholder":"Search","hotkeys":["/"],"noResultsFoundMsg":"No Results","recognizeLanguages":true,"languages":[0],"preload":true},"resources":{"History_Title_Label":"History","History_ClearLink_Label":"Clear","History_NoHistory_Label":"No history items","API_AccessFilter_Label":"Access","API_ParameterSection_Label":"PARAMETERS","API_SignatureSection_Label":"SIGNATURE","API_CopyHint_Label":"Copy","API_CopyNameHint_Label":"Copy name","API_CopyLinkHint_Label":"Copy link","API_CopiedAckHint_Label":"Copied!","API_MoreOverloads_Label":"more","API_MoreDropdownItems_Label":"More","API_OptionalParameter_Label":"optional","API_DefaultParameterValue_Label":"Default value","API_InheritedFilter_Label":"Inherited","Search_Input_Placeholder":"Search","Toc_Contents_Label":"Contents","Toc_RelatedClasses_Label":"Related Classes","History_JustNowTime_Label":"just now","History_AgoTime_Label":"ago","History_YearTime_Label":"y","History_MonthTime_Label":"mo","History_DayTime_Label":"d","History_HourTime_Label":"h","History_MinuteTime_Label":"m","History_SecondTime_Label":"s"}};
diff --git a/resources/js/search.js b/resources/js/search.js
index e51dc0c..b17dbad 100644
--- a/resources/js/search.js
+++ b/resources/js/search.js
@@ -1 +1 @@
-window.__DOCS_SEARCH__ = [[{"i":"#","p":["Nitrite is a serverless, embedded, and self-contained NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Welcome to Nitrite Database","p":["NO sql O bject ( NO2 a.k.a Nitrite) is a serverless, embedded, and self-contained NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use. Currently, it is available in Java, Kotlin, and Flutter.","Nitrite database can be used in various scenarios where a lightweight, embedded, and serverless NoSQL database is required. Some of the use cases for Nitrite database are:","Mobile and desktop applications","IoT devices and sensors","Web applications and APIs","Prototyping and testing","Data caching and synchronization","Data analysis and reporting","Nitrite database is designed to be simple and easy to use, making it a good choice for small to medium-sized projects that require a fast and reliable data storage solution."]},{"i":"features","l":"✨ Features","p":["Embedded, serverless","Simple API","Document-oriented","Schemaless document collection and object repository","Extensible storage engines","Indexing and full-text search","Simple query api","In-memory and file-based store","Transaction support","Schema migration support","Encryption support"]},{"i":"what-nitrite-is-not","l":"⛔ What Nitrite is not","p":["Nitrite is not an RDBMS. It is also not a distributed NoSQL database like MongoDB or Cassandra. It does not have any server for external application to connect to."]},{"i":"getting-started","l":"\uD83D\uDE80 Getting Started","p":["Nitrite database is currently available in Java, Kotlin, and Flutter. Please visit respective language page for getting started guide.","Java","Kotlin","Flutter"]},{"i":"license","l":"\uD83D\uDCDD License","p":["Nitrite database is an open-source project released under the terms of the Apache License, Version 2.0."]},{"i":"support","l":"\uD83E\uDD1D Support","p":["Give a ⭐️ if this project helped you! Please consider donating to support the development and maintenance."]},{"i":"contributing","l":"\uD83D\uDC9A Contributing","p":["Contributions, issues and feature requests are welcome. Feel free to open a discussion thread here."]},{"i":"showcase","l":"\uD83C\uDF9E️ Showcase","p":["If you are using Nitrite database in your project, please let us know. We will be happy to showcase your project here."]}],[{"i":"#","p":["This guide will help you get started with Nitrite database. It will show you how to create a database, create a collection, insert documents, and query documents in Java."]},{"l":"Getting Started in Java","p":["To get started with Nitrite database, you need to add the Nitrite BOM to your project. The BOM will help you to manage the dependencies. Details of the BOM can be found here.","To add the BOM to your project, follow the steps below:"]},{"l":"Add dependency","p":["Add Nitrite dependency to your project:"]},{"l":"Maven","p":["Add the nitrite dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite dependency to your build.gradle file:","The latest released version of Nitrite can be found here."]},{"l":"Snapshot builds","p":["Snapshot builds are available from Sonatype.","To use snapshot builds, you need to add the following repository to your pom.xml file:","Or, if you are using Gradle, add the following repository to your build.gradle file:","You need Java 11 or above to use Nitrite database."]},{"i":"upgrade-from-3x","l":"Upgrade from 3.x","p":["If you are upgrading from 3.x, please note that there are lots of breaking changes in the API. The whole library is re-written from scratch. It is recommended to go through this guide before upgrading.","You need to use the MVStore as your storage module to upgrade from 3.x. The RocksDB module is not backward compatible.","Nitrite will try to migrate your existing database to the latest version on the provided you are using the MVStore module. If you are using the RocksDB module, you need to migrate your database manually. However, it is recommended to take a backup of your database before upgrading."]}],[{"l":"Nitrite Database","p":["Nitrite database is a serverless, embedded, and self-contained Java NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Creating a Database","p":["Nitrite database can be created in-memory or on-disk. By default, Nitrite database is created in-memory. To create a database on-disk, you need to add a storage module dependency to your project. More details about storage modules can be found here.","To create a database, you need to use NitriteBuilder class. To get an instance of NitriteBuilder, you need to call builder() method on Nitrite class."]},{"l":"In-memory Database","p":["If you don't load any on-disk storage module, then Nitrite will create an in-memory database. The below code snippet shows how to create a database in-memory."]},{"l":"On-disk Database","p":["The below code snippet shows how to create a database on-disk."]},{"l":"MVStore Backed Database","p":["More details about MVStore configuration can be found here."]},{"l":"RocksDB Backed Database","p":["More details about RocksDB configuration can be found here."]},{"l":"NitriteBuilder","p":["NitriteBuilder provides a fluent API to configure and create a Nitrite database instance."]},{"l":"Open or Create a Database","p":["To open or create a database, you need to call openOrCreate() method on NitriteBuilder instance. This method returns a Nitrite instance.","If no StoreModule is configured, then Nitrite will create an in-memory database. If a StoreModule is configured, then Nitrite will create a file-based database. If the database file does not exist, then Nitrite will create a new database file. If the database file already exists, then Nitrite will open the existing database file."]},{"l":"Securing a Database","p":["To secure a database, you need to call openOrCreate() method with username and password on NitriteBuilder instance. This method returns a Nitrite instance with the given username and password.","If you are using a file-based database, then you need to use the same username and password to open the database again. Otherwise, you will get a NitriteSecurityException.","Both username and password must be provided or both must be null."]},{"l":"Registering an EntityConverter","p":["Nitrite database uses a mapper to map Java entities to Nitrite documents and vice-versa. By default, Nitrite uses SimpleNitriteMapper as its mapper. This mapper uses EntityConverter s to map Java entities to Nitrite documents and vice-versa. To register an EntityConverter, you need to call registerEntityConverter() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More on EntityConverter can be found here."]},{"l":"Loading a Module","p":["Nitrite database is modular in nature. It provides various modules to extend its functionality. To load a module, you need to call loadModule() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance."]},{"l":"Loading a Storage Module"},{"l":"Loading a Jackson Based Mapper Module","p":["More on the Nitrite's module system can be found here."]},{"l":"Adding Migration Steps","p":["Nitrite database supports schema migration. To configure a migration step, you need to call addMigrations() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More on the schema migration can be found here."]},{"l":"Current Schema Version","p":["To configure the current schema version, you need to call schemaVersion() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","By default, the initial schema version is set to 1."]},{"l":"Field Separator Character","p":["To configure the field separator character, you need to call fieldSeparator() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","It is used to separate field names in a nested document. For example, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax.","The default field separator character is set to .."]}],[{"l":"Document","p":["Document is the basic unit of data in Nitrite database. It is a JSON like field-value pairs. The field is always a String and value can be anything including null. Document is schema-less, which means you can store any kind of data in a document.","Nitrite document supports nested document. That means, a value of a field can be another document. This allows you to create complex data structure."]},{"l":"Document Structure","p":["Nitrite document has the following structure."]},{"l":"Document Field","p":["Document field is always a String. It can be any valid string. The field cannot be null or empty string.","Below fields are reserved and cannot be used as key in a document.","_id: The unique identifier of a document. This field is auto-generated by Nitrite database during insertion.","_revision: The revision number of a document. This field is auto-generated by Nitrite database during insertion and update.","_source: The source collection name of a document.","_modified: The last modified timestamp of a document. This field is auto-generated by Nitrite database during insertion and update."]},{"l":"Document Value","p":["Document value can be any valid Java object. It can be null or any primitive type. It can also be a collection or an array. It can also be a nested document."]},{"l":"Document Identifier","p":["It is a unique identifier of a document. It is auto-generated by Nitrite database during insertion. It is a NitriteId and is stored as a String in the document."]},{"l":"NitriteId","p":["NitriteId is a unique identifier across the Nitrite database. Each document in a nitrite collection is associated with a NitriteId.","During insertion if a unique String value representing a 64-bit integer is supplied in the _id field of the document, then the value of the _id field will be used to generate the NitriteId. Otherwise, a new NitriteId will be generated and will be used in the _id field of the document.","The value of the NitriteId is a String representation of a 64-bit integer. The id generation is based on Twitter Snowflake algorithm. The id is composed of:","41 bits for time in milliseconds","10 bits for a machine id","12 bits for a sequence number","1 unused sign bit","The id is not guaranteed to be monotonically increasing. The id is sortable and the timestamp is stored in the id itself."]},{"l":"Retrieving a NitriteId from a Document","p":["The id can be retrieved from a document using Document.getId() method. If the document does not have an id, then it will create a new NitriteId and will set it in the document and will return the id. If the document already has an id, then it will return the id."]},{"l":"Field Separator","p":["To access a field of a nested document, or an element of an array field, you need to use the field separator.","Field separator is configurable. You can change the field separator character by calling NitriteBuilder.fieldSeparator() method.","Nitrite uses . as field separator by default."]},{"l":"Nested Document","p":["To specify or access a field of a nested document, you need to use the field separator character. That means, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax."]},{"l":"Array Field","p":["To specify or access an element of an array field, you need to use the index of the element. For example, if a document has a field phone which is an array, then the first element of the array can be accessed using phone.0 syntax."]},{"l":"Creating a Document","p":["To create a document, you need to use Document.createDocument() method."]},{"l":"Creating an Empty Document"},{"l":"Creating a Document with Initial Field-value Pair"},{"l":"Creating a Document with a Map"},{"l":"Updating a Document","p":["To update a document, you need to use Document.put() method. This method takes two parameters, the field name and the value. If the field already exists in the document, then the value will be updated. If the field does not exist, then it will be created."]},{"l":"Retrieving a Value from Document","p":["To retrieve a value from document, you need to use Document.get() method. This method takes one parameter, the field name. If the field exists in the document, then the value will be returned. If the field does not exist, then it will return null.","To retrieve a value from a nested document, use the field separator character.","To retrieve an element from an array field, use the index of the element."]},{"l":"Removing a Field from Document","p":["To remove a field from document, you need to use Document.remove() method. This method takes one parameter, the field name. If the field exists in the document, then it will be removed. If the field does not exist, then it will do nothing.","To remove a field from a nested document, use the field separator character.","To remove an element from an array field, use the index of the element."]},{"l":"Checking If a Field Exists in Document","p":["To check if a field exists in a document, you need to use Document.containsField() method. This method takes one parameter, the field name. If the field exists in the document, then it will return true. If the field does not exist, then it will return false.","To check if a field exists in a nested document, use the field separator character.","It cannot check if an element exists in an array field."]}],[{"l":"Introduction","p":["NitriteCollection represents a named document collection stored in a Nitrite database. It persists documents in a Nitrite database. It is similar to a table in relational database or a collection in MongoDB.","Each document in a collection is associated with a unique NitriteId. It exposes a set of methods to perform CRUD operations on documents. It also supports indexing and querying. It also supports event based notification on document changes.","NitriteCollection is thread-safe and supports concurrent read and write operations."]},{"l":"Creating a Collection","p":["A NitriteCollection can be created using Nitrite class. You need to call getCollection() method on Nitrite class to get an instance of a NitriteCollection.","If the collection does not exist, then it will be created automatically. If a collection with the same name already exists, then it will return the existing collection."]},{"l":"Limitations on Collection Name","p":["A collection name cannot be null or empty string. It cannot contains any of the following characters:","|(pipe)",":(colon)","+(plus)","The name also cannot be any of the following reserved words:","$nitrite_users","$nitrite_index_meta","$nitrite_index","$nitrite_meta_map","$nitrite_store_info","$nitrite_catalog"]}],[{"l":"Write Operations"},{"l":"Inserting Documents","p":["Documents can be inserted into a collection using insert() method. It takes one or multiple Document objects as input parameter. It returns a WriteResult object.","If the document has a NitriteId already in it's _id field, then it will be used as a unique key to identify the document in the collection. Otherwise, a new NitriteId will be generated and inserted into the document.","If any of the field is already indexed in the collection, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.Insert event."]},{"l":"Inserting a Single Document"},{"l":"Inserting Multiple Documents"},{"l":"Error Scenarios","p":["If the document is null, then it will throw a ValidationException.","If the document contains invalid value in it's _id field, then it will throw a InvalidIdException.","If there is another document with the same _id value in the collection, then it will throw a UniqueConstraintException.","If a field of the document is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["WriteResult contains the result of a write operation. It contains the following information:","Number of documents affected by the write operation. You can get this value using getAffectedCount() method.","List of NitriteId of the documents affected by the write operation. The WriteResults implements IterableNitriteId interface. So you can iterate over the WriteResult to get the NitriteId of the documents affected by the write operation."]},{"l":"Updating Documents","p":["Documents can be updated in a collection using update() method. There are several overloaded version of update() method. You can update a single document or multiple documents at a time. You can also update a document using a filter.","This operation will notify all the registered CollectionEventListener with EventType.Update event."]},{"l":"Updating a Single Document","p":["You can update a single document using update() method. It takes a Document object as input parameter. It returns a WriteResult object. The document must contain a valid NitriteId in it's _id field. The document must not be null.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Document","p":["You can upsert a single document using update() method. It takes a Document object as the first input parameter. It takes a boolean value as the second input parameter. If the second input parameter is true, then it will insert the document if it does not exist in the collection. Otherwise, it will update the document if it exists in the collection. It returns a WriteResult object. The document must not be null."]},{"l":"Updating Using a Filter","p":["You can update multiple documents using a filter. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It returns a WriteResult object. The document must not be null or empty.","If the filter result matches multiple documents, then all the documents will be updated."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It takes a UpdateOptions object as the third input parameter. It returns a WriteResult object. The document must not be null or empty."]},{"l":"UpdateOptions","p":["UpdateOptions is a class that contains several options for update operation. It has the following options:","insertIfAbsent: If this option is true, then it will insert the document if it does not exist in the collection. Otherwise, it will update the document if it exists in the collection.","justOnce: If this option is true, then it will update only the first document matched by the filter. Otherwise, it will update all the documents matched by the filter."]},{"l":"Removing Documents","p":["Documents can be removed from a collection using remove() method. There are several overloaded version of remove() method. You can remove a single document or multiple documents at a time using a filter.","This operation will notify all the registered CollectionEventListener with EventType.Remove event."]},{"l":"Removing a Single Document","p":["You can remove a single document using remove() method. It takes a Document object as input parameter. It returns a WriteResult object. The document must contain a valid NitriteId in it's _id field. The document must not be null.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple documents using a filter. It takes a Filter object as the input parameter. It returns a WriteResult object.","If the filter result matches multiple documents, then all the documents will be removed."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a boolean value as the second input parameter. If the second input parameter is true, then it will remove only the first document matched by the filter. Otherwise, it will remove all the documents matched by the filter. It returns a WriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["You can search documents in a collection using find() method. There are several overloaded version of find() method using a filter or find options or both. You can also search a document using it's NitriteId."]},{"l":"Filters","p":["Nitrite uses filters to find documents in a collection. A filter is a simple expression which evaluates to true or false. More information about filters can be found here."]},{"l":"Find All Documents","p":["You can find all documents in a collection by calling find(). It returns a DocumentCursor object."]},{"l":"Finding a Document Using NitriteId","p":["You can find a document using it's NitriteId by calling getById(). It takes a NitriteId as input parameter. It returns a Document object if the document is found. Otherwise, it returns null."]},{"l":"Finding a Document Using a Filter","p":["You can find a document using a filter. It takes a Filter object as input parameter. It returns a DocumentCursor object.","If there is an index on the field specified in the filter, this operation will use the index to find the document. Otherwise, it will scan the entire collection to find the document."]},{"l":"Finding a Document Using a Filter and Options","p":["You can find a document 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 DocumentCursor object."]},{"l":"FindOptions","p":["FindOptions is a class that contains several options for find operation. It has the following options:","limit: It specifies the maximum number of documents to be returned by the find operation.","skip: It specifies the number of documents to be skipped from the beginning of the result set.","orderBy: It specifies a collection of fields to be sorted by, along with sort order for each field. The sort order can be SortOrder.Ascending or SortOrder.Descending.","collator: It specifies a collator to be used for sorting. If this option is not specified, then the default collator will be used.","distinct: It specifies if the find operation should return distinct documents. If this option is true, then it will return only the distinct documents. Otherwise, it will return all the documents matched by the filter."]},{"l":"DocumentCursor","p":["DocumentCursor represents a result set of a find operation. It provides methods to iterate over the result of a find operation and retrieve the documents. It also provides methods like projection, join etc. to get the desired result."]},{"l":"Iterating over Documents","p":["The DocumentCursor extends Iterable interface. So, you can iterate over the documents using for-each loop.","A DocumentCursor is a lazy iterable. It does not load all the documents in memory at once. It loads the documents in memory as needed. So, it is memory efficient."]},{"l":"Getting the Documents","p":["You can get the documents at once using toList() and toSet() methods. It returns a List and Set of documents respectively."]},{"l":"Getting the First Document","p":["You can get the first document using firstOrNull() method. It returns the first document if the cursor has any document. Otherwise, it returns null."]},{"l":"Getting the Size of the Result Set","p":["You can get the size of the result set using size() method. It returns the number of documents in the result set."]},{"l":"Projection","p":["You can project the result set using project() method. It takes a Document as the only input parameter. It returns a RecordStreamDocument object.","The document must contain only the fields that needs to be projected. The field values must be null or a nested document. The condition holds true for nested documents as well.","Let's say you have a document like this:","And you want to project only lastName and address.street fields. Then you can do it like this:","The result set will contain only lastName and address.street fields."]},{"l":"Join","p":["You can join two cursors using join() method. It takes a DocumentCursor as the first input parameter. It takes a Lookup as the second input parameter. It returns a RecordStream object.","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 collections users and orders. The users collection contains the following documents:","And the orders collection contains the following documents:","Now, you want to join these two collections on userId field. Then you can do it like this:","The result set will contain the following documents:"]},{"l":"FindPlan","p":["FindPlan is a class that contains the execution plan of a find operation. It has the following properties:","byIdFilter: It contains the filter for finding a document using NitriteId.","indexScanFilter: It contains the filter for finding a document using index.","collectionScanFilter: It contains the filter for finding a document using full scan.","indexDescriptor: It contains the index descriptor for finding a document using index.","indexScanOrder: It contains the sort order for finding a document using index.","blockingSortOrder: It contains the sort order for finding a document using full scan.","skip: It contains the number of documents to be skipped from the beginning of the result set.","limit: It contains the maximum number of documents to be returned by the find operation.","distinct: It specifies if the find operation returns distinct documents.","collator: It specifies a collator to be used for sorting.","subPlans: It contains the sub plans for finding a document using or filter.","You can get the execution plan of a find operation using getFindPlan() method. It returns a FindPlan object."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a collection. It supports indexing on a single field or multiple fields. It also supports full-text indexing."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in a document. It is useful when you want to search text content in a document. It is also useful when you want to search text content in a document in a language other than English.","Document's _id field is always indexed.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. You need to implement NitriteIndexer interface to create your own custom index. NitriteIndexer is a NitritePlugin, so you need to register it using loadModule() method while opening a database. During index creation you need to pass the type of the custom index in IndexOptions object.","One of such custom index implementation can be found in spatial module. It provides spatial indexing on a collection. More on spatial indexing can be found here."]},{"l":"Creating an Index","p":["You can create an index on a collection using createIndex() method. There are several overloaded version of createIndex() method. You can create an index on a single field or multiple fields."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.NON_UNIQUE in IndexOptions object and the name of the fields on which the index will be created as input parameters."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field by passing the index type as IndexType.FULL_TEXT in IndexOptions object and the name of the field on which the index will be created as input parameters.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Array Field","p":["Nitrite supports creating index on array field. It will create index on each element of the array. For example, if you have a document like this:","You can create index on phones field like this:"]},{"l":"Creating Index on Nested Field","p":["You can create index on nested field. For example, if you have a document like this:","You can create a unique index on street field like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index on a collection using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index on a collection using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes on a collection using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes on a collection using listIndices() method. It returns a Collection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a simple class which contains the following information about an index:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists on a collection using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the collection on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Collection","p":["You can get the size of a collection using size() method. It returns the number of documents in the collection."]},{"l":"Clearing a Collection","p":["You can clear all the documents from a collection using clear() method. It removes all the documents from the collection and index entries from the indexes. It does not drop the collection."]},{"l":"Dropping a Collection","p":["You can drop a collection using drop() method. It removes all the documents from the collection and index entries from the indexes. It also drops all the indexes associated with the collection. It also removes the collection from the database.","You can call isDropped() method to check if the collection is dropped or not.","Any further operation on a dropped collection will throw NitriteIOException."]},{"l":"Closing a Collection","p":["You can close a collection using close() method. Any further operation on a closed collection will throw NitriteIOException.","After closing a collection, you must re-open it via Nitrite.getCollection() method to perform any operation on it.","You can call isOpen() method to check if the collection is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a collection to get notified on document changes. The event listener must implement CollectionEventListener interface. It will receive CollectionEventInfo whenever a document is inserted, updated or removed from the collection.","You can also remove an event listener from a collection."]},{"l":"CollectionEventInfo","p":["CollectionEventInfo contains the following information:","item- the document which is inserted, updated or removed.","originator- the name of the collection on which the event is fired.","eventType- the type of the event. It can be any of the following:","EventType.Insert","EventType.Update","EventType.Remove","EventType.IndexStart","EventType.IndexEnd","timestamp- the timestamp of the event."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a collection.","You can get/set attributes on a collection. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processors are used to process documents before writing them into or after reading them from a collection.","Processors are useful when you want to add some additional information in a document or transform any field before inserting or updating it in a collection. Processors are also useful when you want to validate a document before inserting or updating it in a collection.","Processors are registered on a collection. A collection can have multiple processors. Processors are executed in the order they are registered."]},{"l":"Registering a Processor","p":["You can register a processor on a collection using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a collection and decrypt a field after reading it from a collection.","More on this is described in Support."]}],[{"l":"Introduction","p":["ObjectRepository provides a simple and type-safe API for storing and retrieving Java objects in a Nitrite database. It is built on top of NitriteCollection and provides a similar API for CRUD operations. It also supports indexing and querying. It also supports event based notification on object changes.","ObjectRepository is thread-safe and supports concurrent read and write operations."]},{"l":"Creating a Repository","p":["An ObjectRepository can be created using Nitrite class. You need to call getRepository() method on Nitrite class to get an instance of an ObjectRepository. If the repository does not exist, then it will be created automatically. If a repository with the same name already exists, then it will return the existing repository.","There are several overloaded methods available to create a repository. You can pass a class type or an EntityDecorator along with an optional string key to create a repository."]},{"l":"Creating a Repository with Class Type","p":["You can create a ObjectRepository by passing a class type to getRepository() method."]},{"l":"Creating a Repository with Class Type and Key","p":["You can create a keyed ObjectRepository by passing a class type and a key to getRepository() method.","One typical use case of this keyed repository is to create a repository for each user in a multi-user application. The key can be the user name or user id. This will ensure that each user will have a separate repository for storing objects."]},{"l":"Creating a Repository with EntityDecorator","p":["A ObjectRepository can be created using EntityDecorator. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"Creating a Repository with EntityDecorator and Key","p":["A keyed ObjectRepository can be created using EntityDecorator and a key. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]}],[{"l":"Entity","p":["An entity is a Java object that can be stored in a Nitrite database. An entity can be a simple POJO or a complex object with nested objects. Every entity in an ObjectRepository is actually converted to a Document before storing in the underlying NitriteCollection. When an entity is converted to a Document, the fields of the entity are mapped to the fields of the Document. While retrieving an entity from the ObjectRepository, the Document is converted back to the entity.","Nitrite uses a NitriteMapper implementation to convert an entity to a Document and vice versa. By default, Nitrite uses an EntityConverter based implementation of NitriteMapper to convert an entity to a Document. You can also provide your own implementation of NitriteMapper to convert an entity to a Document.","More on NitriteMapper can be found here."]},{"l":"Annotations","p":["Nitrite uses annotations to define an entity. There are several annotations available to define an entity. These annotations are:","@Entity","@Id","@Index","@Indices","@InheritIndices","In case you cannot modify the entity class to add annotations, you can use EntityDecorator to add metadata to an entity. More on EntityDecorator can be found here."]},{"i":"entity","l":"@Entity","p":["@Entity annotation is used to mark a class as an entity. It is a class level annotation and takes optional value and indices parameters.","The value parameter is used to specify the name of the NitriteCollection in which the entity will be stored as a Document. If the value parameter is not specified, then the name of the collection will be the name of the class. The indices parameter is used to specify the indices on the repository."]},{"i":"id","l":"@Id","p":["@Id annotation is used to mark a field as the unique identifier of the entity. It is a field level annotation and takes optional fieldName parameter. The fieldName parameter is used to specify the name of the field in the document. If the fieldName parameter is not specified, then the name of the field in the class will be used as the name of the field in the document."]},{"l":"Embedded Id","p":["Nitrite also supports embedded id. The embedded id is used when the entity has a composite primary key. The @Id annotation can also be used to mark a field as an embedded id. In case of embedded id, the field should be marked with @Id annotation and the fieldName and embeddedFields parameters should be specified. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","The above @Id annotation will create a unique compound index on the fields - emp_Id.uniqueId and emp_Id.companyId."]},{"l":"Data Type","p":["The data type of the field marked with @Id annotation can be either Comparable or NitriteId. If the data type is Comparable, then the value of the field should be unique. If the data type is NitriteId, then the value of the field will be generated by Nitrite. But in the case of embedded id, the data type of the embedded fields can only be Comparable, it can't be NitriteId."]},{"i":"index","l":"@Index","p":["@Index annotation is used to declare an index on an entity field. It is a class level annotation and takes mandatory fields parameter and optional type parameter. The fields parameter is used to specify the names of the fields in the document to be indexed. The type parameter is used to specify the type of the index. If the type parameter is not specified, then the type of the index will be IndexType.UNIQUE."]},{"i":"indices","l":"@Indices","p":["@Indices annotation is used declare multiple indices on an entity. It is a class level annotation and takes mandatory value parameter. The value parameter is used to specify the list of @Index annotations."]},{"i":"inheritindices","l":"@InheritIndices","p":["@InheritIndices annotation is used to inherit the indices from the parent class. It is a class level annotation and takes no parameter.","If the @InheritIndices annotation is not specified, then the indices will not be inherited from the parent class."]},{"l":"EntityDecorator","p":["EntityDecorator is used to add metadata to an entity. If you cannot modify the entity class to add annotations, then you can use EntityDecorator to add metadata to an entity. You can use EntityDecorator to add id, indices and collection name for an entity.","While creating or opening a repository, you can pass an instance of EntityDecorator to the getRepository() method on Nitrite class. Nitrite will extract the metadata from the EntityDecorator instance and use it to create the repository.","To write an EntityDecorator for an entity, you need to implement the EntityDecorator interface. Let's take an example of a Product entity.","The Product entity has an embedded id ProductId and two indices on a nested object Manufacturer. To write an EntityDecorator for the Product entity, you need to implement the EntityDecorator interface as follows.","which is equivalent to the following entity class."]},{"l":"EntityId","p":["EntityId is used to specify the id field of an entity. It takes mandatory fieldName parameter and optional embeddedFields parameter in case of embedded id. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","Here productId is the name of the field in the document and uniqueId and productCode are the names of the fields in the embedded object. This will create a unique compound index on the fields - productId.uniqueId and productId.productCode."]},{"l":"EntityIndex","p":["EntityIndex is used to specify the indices on an entity. It takes mandatory type parameter and fields parameter. The type parameter is used to specify the type of the index. The fields parameter is used to specify the name of the fields in the document to be indexed.","Here manufacturer.name is the name of the field in the document and productName and manufacturer.uniqueId are the names of the fields in the document. This will create a non-unique index on the field manufacturer.name and a unique compound index on the fields - productName and manufacturer.uniqueId."]},{"l":"Entity Name","p":["Entity name is used to specify the name of the collection in which the entity will be stored. It takes no parameter.","Here product is the name of the NitriteCollection in which the product document will be stored."]}],[{"l":"NitriteMapper","p":["NitriteMapper is a simple and lightweight object mapper which can be used to map Java objects to Nitrite documents and vice-versa. Nitrite uses a NitriteMapper implementation to map Java entities to Nitrite documents and vice-versa while storing and retrieving objects from an ObjectRepository."]},{"l":"SimpleNitriteMapper","p":["Nitrite provides a default NitriteMapper implementation called SimpleNitriteMapper. This is a simple and lightweight mapper which uses EntityConverter to map a Java object to Nitrite documents and vice-versa. This mapper is suitable for most of the use cases."]},{"l":"EntityConverter","p":["EntityConverter is a simple interface which provides methods to convert a Java object to Nitrite document and vice-versa. For each class, you need to provide an implementation of EntityConverter and register it with SimpleNitriteMapper. SimpleNitriteMapper will use this converter to map the object to Nitrite document and vice-versa.","Let's take an example of Product class.","To map this to Nitrite document, we need to provide an implementation of EntityConverter for each class. Let's take a look at the converter for Product class.","Similarly, we need to provide converter for ProductId and Manufacturer class.","Once the converters are ready, we need to register them with registerEntityConverter() method on NitriteBuilder instance.","we can also register the converters with SimpleNitriteMapper instance and then pass the instance to loadModule() method.","NitriteMapper is a NitritePlugin. So, you need to load it using loadModule() method on NitriteBuilder. More on Nitrite's module system can be found here.","If you have used the registerEntityConverter() method on NitriteBuilder instance, Nitrite will only use SimpleNitriteMapper to map the entities. It will ignore any other NitriteMapper implementation you have provided using loadModule() method."]},{"l":"JacksonMapper","p":["Nitrite also provides a Jackson based mapper called JacksonMapper. This mapper uses Jackson's ObjectMapper to map Java entities to Nitrite documents and vice-versa. Here you don't need to provide any EntityConverter. Jackson will use its own ObjectMapper to map the entities.","More on this mapper can be found here."]},{"l":"Custom NitriteMapper","p":["Apart from SimpleNitriteMapper and JacksonMapper, you can also provide your own implementation of NitriteMapper. You need to implement NitriteMapper interface and provide your own implementation. Once the implementation is ready, you need to load it using loadModule() method on NitriteBuilder while building the database."]}],[{"l":"Write Operations"},{"l":"Inserting Entities","p":["Entities can be inserted into a repository using insert() method. It takes one or multiple Java entities as input parameter. It returns a WriteResult object.","If the entity has a NitriteId field, then the field value would be populated with a new NitriteId before inserting into the repository.","If any of the field is already indexed in the repository, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.Insert event."]},{"l":"Inserting a Single Entity"},{"l":"Inserting Multiple Entities"},{"l":"Error Scenarios","p":["If the entity is null, then it will throw a ValidationException.","If a field of the entity is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["More information about WriteResult can be found here."]},{"l":"Updating Entities","p":["Entities can be updated in a repository using update() method. There are several overloaded methods available for updating entities. All of them returns a WriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.Update event."]},{"l":"Updating a Single Entity","p":["You can update a single entity using update() method. It takes a Java entity as input parameter. It returns a WriteResult object.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the getIdField() method must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Entity","p":["You can upsert a single entity using update() method. It takes a Java entity as first input parameter. It takes a boolean value as second input parameter. If the second input parameter is true, then it will insert the entity if it does not exist in the repository. Otherwise, it will update the entity if it exists in the repository. It returns a WriteResult object."]},{"l":"Updating Using a Filter","p":["You can update multiple entities using a filter. It takes a Filter object as first input parameter. It takes a Java entity as second input parameter. It returns a WriteResult object. The entity must not be null.","If the filter result matches multiple entities, then all the entities will be updated."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a Java entity as second input parameter. It takes a UpdateOptions object as third input parameter. It returns a WriteResult object. The entity must not be null."]},{"l":"UpdateOptions","p":["More information about UpdateOptions can be found here."]},{"l":"Updating Using a Filter and Document","p":["You can update multiple entities using a filter and document. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It returns a WriteResult object. The document must not be null or empty.","If the filter result matches multiple entities, then all the entities will be updated. The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"i":"updating-using-a-filter-document-and-options","l":"Updating Using a Filter, Document and Options","p":["You can update multiple entities using a filter, document and options. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It takes a boolean value as third input parameter. If the third input parameter is true, then it will only update the first entity matched by the filter. Otherwise, it will update all the entities matched by the filter. It returns a WriteResult object. The document must not be null or empty.","The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"l":"Removing Entities","p":["Entities can be removed from a repository using remove() method. There are several overloaded methods available for removing entities. All of them returns a WriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.Remove event."]},{"l":"Removing a Single Entity","p":["You can remove a single entity using remove() method. It takes a Java entity as input parameter. It returns a WriteResult object.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the getIdField() method must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple entities using a filter. It takes a Filter object as input parameter. It returns a WriteResult object.","If the filter result matches multiple entities, then all the entities will be removed."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a boolean value as second input parameter. If the second input parameter is true, then it will remove only the first entity matched by the filter. Otherwise, it will remove all the entities matched by the filter. It returns a WriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["You can search entities in a repository using find() method. There are several overloaded version of find() method using a filter or find options or both. You can also search an entity using it's id."]},{"l":"Filters","p":["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."]},{"l":"Find All Entities","p":["You can find all entities in a repository by calling find(). It returns a Cursor object."]},{"l":"Finding an Entity Using Id","p":["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."]},{"l":"Finding an Entity Using a Filter","p":["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."]},{"l":"Finding an Entity Using a Filter and Options","p":["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."]},{"l":"FindOptions","p":["More information about FindOptions can be found here."]},{"l":"Cursor","p":["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."]},{"l":"Iterating over Entities","p":["The Cursor extends Iterable interface. So, you can iterate over the entities using for-each loop.","A Cursor is a lazy iterable. It will not load all the entities in memory at once. It will load the entities in memory as needed. So, it is memory efficient."]},{"l":"Getting the Entities","p":["You can get the entities from the cursor at once using toList() and toSet() method. It returns a List and Set of entities respectively."]},{"l":"Getting the First Entity","p":["You can get the first entity from the cursor using firstOrNull() method. It returns the first entity if the cursor is not empty. Otherwise, it returns null."]},{"l":"Getting the Size of the Cursor","p":["You can get the size of the cursor using size() method. It returns the number of entities in the cursor."]},{"l":"Projection","p":["You can project the cursor using project() method. It takes another entity type as input parameter. It returns a Cursor object of the projected entity.","The projected entity must contain only the fields that needs to be projected.","Let's say you have an entity like this:","And you want to project only lastName and address.street fields. Then you can define a new entity like this:","And then you can project the cursor like this:"]},{"l":"Join","p":["You can join two cursors using join() method. It takes another cursor as the first input parameter. It takes a Lookup as the second input parameter and type of the join as the third input parameter. It returns a RecordStream object.","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:","And you want to join these two entities using userId field. Then you can define a new entity like this:","And then you can join the cursors like this:"]},{"l":"FindPlan","p":["You can get the FindPlan of a cursor using getFindPlan() method. It returns a FindPlan object.","More information about FindPlan can be found here."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a repository. It supports indexing on a single field or multiple fields. It also supports full-text indexing.","Indexes for an entity can be defined using various annotations like @Id, @Index, @Indices etc. More information about annotations can be found here. It can also be managed using various methods of ObjectRepository interface."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in an entity. It is useful when you want to search text content in an entity. It is also useful when you want to search text content in an entity in a language other than English.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. More information about custom index can be found here."]},{"l":"Creating an Index","p":["You can define indexes for an entity using annotations. You can also create indexes using ObjectRepository interface."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Using Annotations","p":["You can create a unique index on a single field or multiple fields using annotations. You can use @Id annotation to create a unique index on a single field. You can use @Index annotation to create a unique index on multiple fields."]},{"l":"Using ObjectRepository","p":["You can create a unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.NON_UNIQUE."]},{"i":"using-annotations-1","l":"Using Annotations","p":["You can create a non-unique index on a single field or multiple fields using annotations. You can use @Index annotation to create a non-unique index on multiple fields."]},{"i":"using-objectrepository-1","l":"Using ObjectRepository","p":["You can create a non-unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.NON_UNIQUE."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field by passing the index type as IndexType.FULL_TEXT."]},{"i":"using-annotations-2","l":"Using Annotations","p":["You can create a full-text index on a single field using annotations. You can use @Index annotation to create a full-text index on a single field."]},{"i":"using-objectrepository-2","l":"Using ObjectRepository","p":["You can create a full-text index on a single field using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.FULL_TEXT.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Array Field","p":["Nitrite supports creating index on array field. It will create index on each element of the array. For example, if you have an entity like this:","You can create index on tags field like this:"]},{"l":"Creating Index on Embedded Field","p":["Nitrite supports creating index on embedded field. For example, if you have entities like this:","You can create index on name of Manufacturer entity via annotation like this:","Or you can create index on name of Manufacturer entity via ObjectRepository like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index on a repository using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index on a repository using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes on a repository using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes on a repository using listIndices() method. It returns a Collection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a simple class which contains the following information about an index:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists on a repository using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the repository on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Repository","p":["You can get the size of a repository using size() method. It returns the number of entities in the repository."]},{"l":"Clearing a Repository","p":["You can clear all the entities from a repository using clear() method. It removes all the entities from the repository and index entries from the indexes. It does not drop the repository."]},{"l":"Dropping a Repository","p":["You can drop a repository using drop() method. It removes all the entities from the repository and index entries from the indexes. It also drops all the indexes associated with the repository. It also removes the repository from the database.","You can call isDropped() method to check if the repository is dropped or not.","Any further operation on a dropped repository will throw NitriteIOException."]},{"l":"Closing a Repository","p":["You can close a repository using close() method. Any further operation on a closed repository will throw NitriteIOException.","After closing a repository, you must re-open it via Nitrite.getRepository() method to perform any operation on it.","You can call isOpen() method to check if the repository is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a repository to get notified on entity changes. The event listener must implement CollectionEventListener interface. It will receive CollectionEventInfo whenever an entity is inserted, updated or removed from the repository.","You can also remove an event listener from a collection."]},{"l":"CollectionEventInfo","p":["More on CollectionEventInfo can be found here."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a repository.","You can get/set attributes on a repository. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processor can be used to process the underlying documents of a repository. More on processors can be found here."]},{"l":"Registering a Processor","p":["You can register a processor on a repository using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a repository and decrypt a field after reading it from a repository.","More on this is described in Support."]}],[{"l":"Filters","p":["Filters are used to specify the criteria used to select documents from a collection or repository. It provides a way to specify conditions that the documents must meet to be included in the result set. Filters are used in conjunction with the find method. The find method returns all documents in a collection that match the specified filtering criteria.","Each filtering criteria is based on a field in the document. If the field is indexed, the find operation takes advantage of the index to speed up the operation. If the field is not indexed, the find operation scans the entire collection to find matching documents."]},{"l":"Fluent API","p":["Nitrite provides a fluent API to create filters via FluentFilter class. It provides a static where method that creates a new FluentFilter instance with the specified field name. Here's an example:","In this example, the FluentFilter.where method is used to create a filter that matches documents where the name field equals John. The filter is then passed to the find method to retrieve the matching documents.","For spatial filters, use the SpatialFluentFilter class for the fluent API. It provides a static where method that creates a new SpatialFluentFilter instance with the specified field name. Here's an example:","More on spatial module can be found here."]},{"l":"Usage","p":["Filters are used with the find method of NitriteCollection or ObjectRepository to retrieve documents or entities that match the filter. Here's an example:","In this example, the where and eq methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Types of Filters","p":["Nitrite filters can be grouped into the following categories:","Comparison filters","Logical filters","Array filters","Evaluation filters","Spatial filters"]},{"l":"Comparison Filters","p":["Comparison filters are used to compare a field with a value. The following comparison filters are supported:","Equality (eq): Matches all documents where the value of the field equals the specified value.","Inequality (notEq): Matches all documents where the value of the field is not equal to the specified value.","Greater than (gt): Matches all documents where the value of the field is greater than the specified value.","Greater than or equal to (gte): Matches all documents where the value of the field is greater than or equal to the specified value.","Less than (lt): Matches all documents where the value of the field is less than the specified value.","Less than or equal to (lte): Matches all documents where the value of the field is less than or equal to the specified value.","In (in): Matches all documents where the value of the field equals any value in the specified array.","Not in (notIn): Matches all documents where the value of the field does not equal any value in the specified array.","Between (between): Matches all documents where the value of the field is between the specified values.","All (all): Matches all documents in the collection."]},{"l":"Equality Filter","p":["The equality filter is used to match documents where the value of a field equals the specified value. The following example shows how to use the equality filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Inequality Filter","p":["The inequality filter is used to match documents where the value of a field is not equal to the specified value. The following example shows how to use the inequality filter:","In this example, the where() and notEq() methods are used to create an inequality filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than Filter","p":["The greater than filter is used to match documents where the value of a field is greater than the specified value. The following example shows how to use the greater than filter:","In this example, the where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than or Equal To Filter","p":["The greater than or equal to filter is used to match documents where the value of a field is greater than or equal to the specified value. The following example shows how to use the greater than or equal to filter:","In this example, the where() and gte() methods are used to create a greater than or equal to filter that matches documents where the age field is greater than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than Filter","p":["The less than filter is used to match documents where the value of a field is less than the specified value. The following example shows how to use the less than filter:","In this example, the where() and lt() methods are used to create a less than filter that matches documents where the age field is less than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than or Equal To Filter","p":["The less than or equal to filter is used to match documents where the value of a field is less than or equal to the specified value. The following example shows how to use the less than or equal to filter:","In this example, the where() and lte() methods are used to create a less than or equal to filter that matches documents where the age field is less than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"In Filter","p":["The in filter is used to match documents where the value of a field equals any value in the specified array. The following example shows how to use the in filter:","In this example, the where() and in() methods are used to create an in filter that matches documents where the name field equals \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not In Filter","p":["The not in filter is used to match documents where the value of a field does not equal any value in the specified array. The following example shows how to use the not in filter:","In this example, the where() and notIn() methods are used to create a not in filter that matches documents where the name field does not equal \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Between Filter","p":["The between filter is used to match documents where the value of a field is between the specified values. The following example shows how to use the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. The filter is then passed to the find method to retrieve the matching documents.","There are three overloaded versions of the between filter. The first version takes two parameters, the lower and upper bounds of the range. The second version takes an additional boolean parameter that indicates whether both the lower and upper bounds are inclusive or exclusive. The third version takes two additional boolean parameters that indicate whether the lower and upper bounds are inclusive or exclusive. The following example shows how to use the second version of the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. Both the lower and upper bounds are inclusive. The filter is then passed to the find method to retrieve the matching documents.","The following example shows how to use the third version of the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. The lower bound is inclusive and the upper bound is exclusive. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"All Filter","p":["The all filter is used to match all documents in the collection. The following example shows how to use the all filter:","In this example, the Filter.ALL constant is used to create an all filter that matches all documents in the collection. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Logical Filters","p":["Logical filters are used to combine multiple filters into a single filter. The following logical filters are supported:","And (and): Matches all documents that satisfy all the specified filters.","Or (or): Matches all documents that satisfy at least one of the specified filters.","Not (not): Matches all documents that do not satisfy the specified filter."]},{"l":"And Filter","p":["The and filter is used to match documents that satisfy all the specified filters. The following example shows how to use the and filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the and() method to create an and filter that matches documents where the name field equals \"John\" and the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The and() method can be used to combine any number of filters. The following example shows how to combine three filters:","The static Filter.and() method can also be used to combine multiple filters into a single filter. The following example shows how to combine two filters into a single filter:","In this example, the and() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Or Filter","p":["The or filter is used to match documents that satisfy at least one of the specified filters. The following example shows how to use the or filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the or() method to create an or filter that matches documents where the name field equals \"John\" or the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The or() method can be used to combine any number of filters. The following example shows how to combine three filters:","The static Filter.or() method can also be used to combine multiple filters into a single filter. The following example shows how to combine two filters into a single filter:","In this example, the or() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not Filter","p":["The not filter is used to match documents that do not satisfy the specified filter. The following example shows how to use the not filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The not() method is then used to create a not filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents.","The not() method can be used to negate any filter. The following example shows how to negate a greater than filter:"]},{"l":"Array Filters","p":["Array filters are used to match documents based on the values in an array field. The following array filters are supported:","Element match (elemMatch): Matches all documents where the array field contains at least one element that matches the specified filter."]},{"l":"Element Match Filter","p":["The element match filter is used to match documents where the array field contains at least one element that matches the specified filter. The following example shows how to use the element match filter:","Let's say we have a collection that contains documents with the following structure:","The following example shows how to use the element match filter to find all documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\":","In this example, the where() and elemMatch() methods are used to create an element match filter that matches documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\". The filter is then passed to the find method to retrieve the matching documents.","The elemMatch filter can be used to search an array of elements for a specific value. The following example shows how to use the elemMatch filter to find all documents where the data field contains at least one element that is greater than 2 or less than equal to 5:","The static FluentFilter.$ is used to create a filter for the current element in the array. The $.gt(2).or($.lte(5)) filter is used to match documents where the data field contains at least one element that is greater than 2 or less than equal to 5. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Evaluation Filters","p":["Evaluation filters are used to match documents based on evaluating the value of any field in a document. The following evaluation filters are supported:","Text (text): Matches all documents which contain a specified full-text search expression.","Regex (regex): Matches all documents where values contain a specified regular expression."]},{"l":"Text Filter","p":["The text filter is used to match documents which contain a specified full-text search expression. The following example shows how to use the text filter:","In this example, the where() and text() methods are used to create a text filter that matches documents where the name field contains the word \"John\". The filter is then passed to the find method to retrieve the matching documents.","The text filter supports glob patterns. The following example shows how to use the text filter with glob patterns:","The text filter can only be used with a field that has a full-text index."]},{"l":"Regex Filter","p":["The regex filter is used to match documents where values contain a specified regular expression. The following example shows how to use the regex filter:","In this example, the where() and regex() methods are used to create a regex filter that matches documents where the name field matches the regular expression \"John.*\". The filter is then passed to the find method to retrieve the matching documents.","This filter scans the entire collection to find matching documents. It cannot take advantage of an index."]},{"l":"Spatial Filters","p":["Spatial filters are used to match documents based on the values in a spatial field. The following spatial filters are supported:","Near (near): Matches all documents where the spatial field is within the specified distance from the specified point.","Within (within): Matches all documents where the spatial field is within the specified shape.","Intersects (intersects): Matches all documents where the spatial field intersects the specified shape.","To use spatial filters, you need create a spatial index on the field, which needs the nitrite-spatial module to be loaded. More on this can be found here.","Spatial filters can only be used with a field that has a spatial index."]},{"l":"Near Filter","p":["The near filter is used to match documents where the value of the spatial field is near the specified point. The following example shows how to use the near filter:","In this example, the where() and near() methods are used to create a near filter that matches documents where the location field is within 1000 meters of the point (40.730610, -73.935242). The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Within Filter","p":["The within filter is used to match documents where the value of the spatial field is within the specified shape. The following example shows how to use the within filter:","In this example, the where() and within() methods are used to create a within filter that matches documents where the location field is within the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Intersects Filter","p":["The intersects filter is used to match documents where the value of the spatial field intersects the specified shape. The following example shows how to use the intersects filter:","In this example, the where() and intersects() methods are used to create an intersects filter that matches documents where the location field intersects the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]}],[{"l":"Transaction","p":["A transaction is a single logical unit of work which accesses and possibly modifies the contents of a database. Transactions access data using read and write operations.","Nitrite supports transactional operations on its collections and repositories. A transaction can be committed or rolled back. Once a transaction is committed, all the changes are persisted to the disk. If a transaction is rolled back, all the changes are discarded."]},{"l":"Transaction on NitriteCollection","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a NitriteCollection, the Transaction.getCollection() method can be used. All the operations performed on the collection will be part of the transaction.","Transaction is a closeable resource. It is recommended to use it with try-with-resource block.","Any find operations performed inside a transaction will return all the documents including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed documents."]},{"l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","NitriteCollection.createIndex()","NitriteCollection.rebuildIndex()","NitriteCollection.dropIndex()","NitriteCollection.dropAllIndices()","NitriteCollection.drop()","NitriteCollection.clear()","NitriteCollection.close()"]},{"l":"Transaction on ObjectRepository","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a ObjectRepository, the Transaction.getRepository() method can be used. All the operations performed on the repository will be part of the transaction.","Transaction is a closeable resource. It is recommended to use it with try-with-resource block.","Any find operations performed inside a transaction will return all the entities including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed entities."]},{"i":"auto-commit-operations-1","l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","ObjectRepository.createIndex()","ObjectRepository.rebuildIndex()","ObjectRepository.dropIndex()","ObjectRepository.dropAllIndices()","ObjectRepository.drop()","ObjectRepository.clear()","ObjectRepository.close()"]},{"l":"Session","p":["A session represents a transactional context for a Nitrite database. Session is used to create a new transaction. A session should be closed after use to release any resources held by it. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Create a Session","p":["A session can be created using the Nitrite.createSession() method. Multiple sessions can be created for a Nitrite database."]},{"l":"Close a Session","p":["A session can be closed using the Session.close() method. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Checking Session State","p":["The current state of a session can be checked using the Session.checkState() method. If the session is not active, it will throw an TransactionException."]},{"l":"Managing Transactions","p":["A transaction can be started using the Session.beginTransaction() method.","A transaction can be committed using the Transaction.commit() method. If a transaction is committed, all the changes are persisted to the disk.","A transaction can be rolled back using the Transaction.rollback() method. If a transaction is rolled back, all the changes are discarded.","A transaction can be closed using the Transaction.close() method. If a transaction is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Querying Transaction State","p":["The current state of a transaction can be retrieved using the Transaction.getState() method. It returns an enum of type TransactionState.","The following states are available:","TransactionState.Active- The transaction is active.","TransactionState.Committed- The transaction is committed.","TransactionState.PartiallyCommitted- The transaction is partially committed.","TransactionState.Closed- The transaction is closed.","TransactionState.Failed- The transaction is failed.","TransactionState.Aborted- The transaction is aborted."]}],[{"l":"Schema Migration","p":["A migration is a set of changes to the schema that can be applied to a database. Migrations are used to keep the database schema up to date with the codebase. It contains a queue of instructions that are executed in order to update the database schema from one version to the next.","The migration is executed only once for a specific schema version. If you want to execute the migration again, you need to change the schema version of the database.","For example, if you have a database with the schema version 1 and you want to update it to version 2, you need to apply the migration steps from version 1 and version 2.","The migration instructions are executed in the order they are added to the migration. The order of the instructions is important. For example, if you want to rename a field, you need to add the renameField instruction before the deleteField instruction. Otherwise, the deleteField instruction will fail.","Once a migration is applied to a database, it cannot be reverted. If you want to revert a migration, you need to create a new migration that will revert the changes.","Nitrite provides a set of instructions that can be used to update the database schema. These instructions can be grouped into three categories:","Database Instruction","Collection Instruction","Repository Instruction"]},{"l":"Database Instruction","p":["Database instructions are used to perform operations on the database. The following instructions are available:"]},{"l":"Add User","p":["Adds an instruction to set a user authentication to the database. The user will be used to open the database.","Nitrite database supports only one user authentication per database. If you try to add a new user when there is already a user authentication present, the migration will fail throwing a NitriteSecurityException."]},{"l":"Change Password","p":["Adds an instruction to change the password for the user authentication to the database.","The user authentication must be present in the database. If you try to change the password for a user that does not exist, the migration will fail throwing a NitriteSecurityException.","If you try to change the password for a user with a wrong password, the migration will also fail throwing a NitriteSecurityException."]},{"l":"Drop Collection","p":["Adds an instruction to drop a NitriteCollection from the database."]},{"l":"Drop Repository","p":["Adds an instruction to drop a ObjectRepository from the database. There are several ways to drop a repository:"]},{"l":"Drop by Class"},{"l":"Drop by Class and Key Name"},{"l":"Drop by EntityDecorator"},{"l":"Drop by EntityDecorator and Key Name"},{"l":"Drop by Repository Type Name"},{"l":"Drop by Repository Type Name and Key Name"},{"l":"Custom Instruction","p":["Adds a custom instruction to perform a user defined operation on the database. The custom instruction is a callback that takes a Nitrite instance as an argument. The callback can be used to perform any operation on the database."]},{"l":"Collection Instruction","p":["Collection instructions are used to perform operations on a NitriteCollection. The following instructions are available:"]},{"l":"Rename Collection","p":["Adds an instruction to rename a NitriteCollection."]},{"l":"Add Field","p":["Adds an instruction to add new field to the documents of a NitriteCollection."]},{"l":"Add Field with Null Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be null."]},{"l":"Add Field with Default Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be new-value."]},{"l":"Add Field with Generator","p":["The new field will be added to all the documents of the collection. The value of the new field will be the value returned by the Generator."]},{"l":"Generator","p":["A Generator is a functional interface that takes a Document as input and returns a value. The value returned by the Generator will be used as the value of the new field."]},{"l":"Rename Field","p":["Adds an instruction to rename a field of the documents of a NitriteCollection."]},{"l":"Delete Field","p":["Adds an instruction to delete a field from the documents of a NitriteCollection."]},{"l":"Drop Index","p":["Adds an instruction to drop an index from a NitriteCollection.","The drop index instruction can be used to drop a single field index or a compound index."]},{"l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a NitriteCollection."]},{"l":"Create Index","p":["Adds an instruction to create an index on a NitriteCollection.","The create index instruction can be used to create a single field index or a compound index."]},{"l":"Repository Instruction","p":["Repository instructions are used to perform operations on a ObjectRepository. The following instructions are available:"]},{"l":"Rename Repository","p":["Adds an instruction to rename a ObjectRepository."]},{"i":"add-field-1","l":"Add Field","p":["Adds an instruction to add new field to the entity of a ObjectRepository."]},{"i":"add-field-with-null-value-1","l":"Add Field with Null Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be null."]},{"i":"add-field-with-default-value-1","l":"Add Field with Default Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be 0."]},{"l":"Add Field with Generator Function","p":["The new field will be added to all the entities of the repository. The value of the new field will be the value returned by the Generator function.","More information about the Generator can be found here."]},{"i":"rename-field-1","l":"Rename Field","p":["Adds an instruction to rename a field of the entity of a ObjectRepository."]},{"i":"delete-field-1","l":"Delete Field","p":["Adds an instruction to delete a field from the entity of a ObjectRepository."]},{"l":"Change Data Type","p":["Adds an instruction to change the data type of a field of the entity of a ObjectRepository."]},{"l":"Type Converter","p":["A TypeConverter is a functional interface that takes a value of one type as input and returns a value of another type. The value returned by the TypeConverter will be used as the value of the new field."]},{"l":"Change Id Field","p":["Adds an instruction to change the id field of the entity of a ObjectRepository."]},{"i":"drop-index-1","l":"Drop Index","p":["Adds an instruction to drop an index from a ObjectRepository.","The drop index instruction can be used to drop a single field index or a compound index."]},{"i":"drop-all-indexes-1","l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a ObjectRepository."]},{"i":"create-index-1","l":"Create Index","p":["Adds an instruction to create an index on a ObjectRepository.","The create index instruction can be used to create a single field index or a compound index."]}],[{"l":"Module System","p":["Nitrite is a modular database engine. The core functionality of Nitrite is provided by the nitrite module. The nitrite module is the only mandatory module for Nitrite. All other modules are optional and can be added to the project as per the requirement.","Nitrite's module system is built on top of NitritePlugin and NitriteModule interfaces. A module is a collection of plugins. While opening a database, all the modules must be loaded. Each module then load and initialize all the plugins it contains.","The nitrite module provides default implementation of all the interfaces. For example, the nitrite module provides in-memory storage implementation. If you want to use on-disk storage, you need to add a storage module to your project.","The main advantage of Nitrite's module system is that it allows you to extend the functionality of Nitrite without adding all the dependencies at once in your project. You only need to add dependencies that you want to use. This helps to keep the application size small.","You can write your own module and plugin and add it to the project. The module system also allows you to replace the default implementation of any plugin. For example, if you want to use a different storage engine, you can write your own storage module and add it to the project."]},{"l":"NitriteModule","p":["The NitriteModule interface is the base interface for all the modules. It encapsulates a set of plugins. A module must be loaded before opening a database.","To create a module, you need to implement the NitriteModule interface. The NitriteModule interface has a single method plugins() which returns a set of plugins."]},{"l":"Dynamic Module","p":["A dynamic module can be created using the static module() method of the NitriteModule interface. A dynamic module is a module which is not loaded from a jar file. It is created at runtime.","A dynamic module is useful when you want to create a module from a set of plugins at runtime."]},{"l":"Available Modules","p":["The following modules are available from Nitrite.","Storage Module","Jackson Module","Spatial Module"]},{"l":"NitritePlugin","p":["The NitritePlugin interface is the base interface for all the plugins. A plugin is a single unit of functionality. A plugin must be loaded via a NitriteModule before opening a database."]},{"l":"Initializing Plugin","p":["A plugin can be initialized by implementing the initialize() method of the NitritePlugin interface. The initialize() method is called by the module when the plugin is loaded."]},{"l":"Closing Plugin","p":["A NitritePlugin is a closable resource. The close method is called by the Nitrite when the plugin is unloaded to release any resources held by the plugin."]},{"l":"Available Plugins","p":["Following are the available plugins in Nitrite which can be used to extend the functionality of Nitrite:","NitriteStore- A plugin to provide storage functionality.","NitriteMapper- A plugin to provide object mapping functionality.","NitriteIndexer- A plugin to provide indexing functionality.","EntityConverter- A plugin to provide entity conversion functionality.","You can implement any of the above plugins to extend the functionality of Nitrite."]},{"l":"NitriteStore","p":["The NitriteStore interface is the base interface for all the storage plugins. A storage plugin is responsible for storing and retrieving data from the underlying storage. The NitriteStore interface extends the NitritePlugin interface.","A reference implementation of the NitriteStore interface can be found here."]},{"l":"NitriteMapper","p":["The NitriteMapper interface is the base interface for all the object mapping plugins. A mapper plugin is responsible for mapping an object to a document and vice-versa. The NitriteMapper interface extends the NitritePlugin interface.","JacksonMapper is one of the available mapper plugins in Nitrite. It uses Jackson to map an object to a document and vice-versa. You can find more information about JacksonMapper here."]},{"l":"NitriteIndexer","p":["The NitriteIndexer interface is the base interface for all the indexing plugins. An indexer plugin is responsible for indexing a document. The NitriteIndexer interface extends the NitritePlugin interface.","While creating a new index, Nitrite uses the getIndexType() method of the NitriteIndexer interface to determine the type of the index. The getIndexType() method returns a string which represents the type of the index. So when you create a new index, you need to pass the same string to the IndexOptions.indexType."]},{"l":"EntityConverter","p":["An EntityConverter is a plugin which is responsible for converting an object to a document and vice-versa. The EntityConverter interface extends the NitritePlugin interface.","If Nitrite is using the default SimpleNitriteMapper, then all EntityConverter s from all the loaded modules are automatically registered with the mapper. If you are using a custom mapper, then you need to register the EntityConverter with the mapper manually.","One of the available EntityConverter in Nitrite is GeometryConverter from the spatial module. It is responsible for converting a Geometry object of JTS to a document and vice-versa. Once you load the spatial module, the GeometryConverter is automatically registered with the mapper. You can find more information about GeometryConverter here.","If you want to load multiple EntityConverter s, while opening the database, you can also create a dynamic module and load it instead of using the NitriteBuilder.registerEntityConverter() method multiple times."]},{"l":"Nitrite Bill of Materials","p":["The nitrite-bom is a bill of materials (BOM) for Nitrite. It is a pom file that contains the version of all the modules. It is useful when you want to use multiple modules in your project and want to keep the version of all the modules in sync."]},{"l":"Maven","p":["Add the nitrite dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite dependency to your build.gradle file:"]}],[{"l":"Storage Module","p":["Nitrite provides a default storage module which is in-memory. It means all the data is stored in memory and is volatile. Once the application is closed, all the data is lost. If you want to persist the data, you want to use on-disk storage, you need to add a storage module to your project. There are choices of storage modules available for Nitrite. You can choose any one of them as per your requirement.","MVStore Module","RocksDB Module","You can also write your own storage module and add it to the project. More details about writing your own storage module is available here."]}],[{"l":"MVStore Modules","p":["Nitrite provides a persistent storage module based on MVStore. MVStore is a pure Java key-value store database. It is a single file based database. It is very fast and lightweight."]},{"l":"Adding MVStore Module","p":["Add MVStore module to your project:"]},{"l":"Maven","p":["Add the MVStore dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the MVStore dependency to your build.gradle file:"]},{"l":"Using MVStore Module","p":["To use MVStore as your persistent storage, you need to load the MVStoreModule while opening the database. You can also configure the module as per your requirement.","Once the module is loaded, you can use the database as usual. All the data will be persisted in the file you specified."]},{"l":"Configuring MVStore Module","p":["You can configure the MVStore module as per your requirement. The following configuration options are available:","filePath- the file path where the database will be stored.","autoCommitBufferSize- the size of the buffer used for auto-commit. When the buffer is full, the changes are automatically committed to the database. The default buffer size is 1024.","encryptionKey- the encryption key used to encrypt the database. If not specified, the database will not be encrypted.","readOnly- if set to true, the database will be opened in read-only mode. The default value is false.","compress- if set to true, the database will be compressed. The default value is false.","compressHigh- if set to true, the database will be compressed using high compression. The default value is false. It may result in slower read and write performance but smaller file size on disk.","autoCommit- if set to true, all changes will be committed immediately. If set to false, changes will be buffered until the buffer is full or Nitrite.commit() is called. The default value is true.","recoveryMode- if set to true, the database will be opened in recovery mode. The default value is false.","cacheSize- the cache size in MB. The default value is 16 MB.","cacheConcurrency- the read cache concurrency used by MVStore. Default is 16 segments.","pageSplitSize- the amount of memory a MVStore page should contain at most, in bytes, before it is split. The default is 16 KB.","fileStore- the file store used by MVStore.","Nitrite provides a builder pattern to configure the module. You can use the MVStoreModule.withConfig() method to get the builder instance. The builder has a build() method which returns the configured module."]},{"i":"upgrading-from-3x","l":"Upgrading from 3.x","p":["If you are upgrading from Nitrite 3.x, you need to use the MVStore module as your storage module if you want to automatically upgrade your database. Any other storage module will not be able to upgrade your database automatically; you need to write your own upgrade logic.","Nitrite 3.x uses MVStore version 1.4.x. Nitrite 4.x uses MVStore version 2.2.x. The MVStore version 2.2.x is not backward compatible with version 1.4.x. So, Nitrite 4.x will try to upgrade your database automatically when you open it for the first time on a . If the upgrade fails, you need to write your own upgrade logic. However, it is recommended to take a backup of your database before upgrading."]}],[{"l":"RocksDB Module","p":["Nitrite provides a persistent storage module based on RocksDB. RocksDB is a persistent key-value store for fast storage. It is based on a log-structured merge-tree (LSM tree) data structure. It is very fast and lightweight. Nitrite uses the JNI wrapper of RocksDB.","RocksDB's column family feature is used to store the data of each collection."]},{"l":"Adding RocksDB Module","p":["Add RocksDB module to your project:"]},{"l":"Maven","p":["Add the RocksDB dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the RocksDB dependency to your build.gradle file:"]},{"l":"Using RocksDB Module","p":["To use RocksDB as your persistent storage, you need to load the RocksDBModule while opening the database. You can also configure the module as per your requirement.","Once the module is loaded, you can use the database as usual. All the data will be persisted in the file you specified."]},{"l":"Configuring RocksDB Module","p":["You can configure the RocksDB module as per your requirement. The following configuration options are available:","filePath- the file path where the database will be stored.","options- the RocksDB's Options object. You can configure RocksDB as per your requirement. The default value is null.","dbOptions- the RocksDB's DBOptions object. You can configure RocksDB as per your requirement. The default value is null.","columnFamilyOptions- the RocksDB's ColumnFamilyOptions object. You can configure RocksDB as per your requirement. The default value is null.","objectFormatter- the ObjectFormatter to be used to serialize/deserialize objects. The default implementation is KryoObjectFormatter which is based on Kryo serializer."]},{"l":"Object Serialization","p":["RocksDB is a key-value store database. It stores data in byte array format. To store objects in RocksDB, Nitrite uses a serializer. Nitrite uses ObjectFormatter to serialize/deserialize objects. The default implementation is KryoObjectFormatter which is based on Kryo serializer. You can also provide your own implementation of ObjectFormatter to serialize/deserialize objects."]},{"l":"Implementing ObjectFormatter","p":["To implement your own ObjectFormatter, you need to implement the ObjectFormatter interface.","Once you have implemented the ObjectFormatter, you can use it while configuring the RocksDB module.","Normally, you don't need to implement your own ObjectFormatter. The default implementation is good enough for most of the use cases."]},{"l":"Limitations","p":["RocksDB JNI does not support RTree, so RocksDB storage adapter does not provide any RTree backed NitriteRTree implementation. Though there is a workaround implementation of NitriteRTree using RocksDB, it is not recommended to use it in production. It is only for testing purpose. Hence, RocksDB storage adapter is not recommended for spatial data indexing.","If you want to use spatial data indexing, you can use Spatial Module with MVStore storage adapter. MVStore storage adapter provides RTree backed NitriteRTree implementation."]}],[{"l":"Custom Storage Modules","p":["The beauty of Nitrite is that it is highly extensible. You can write your own storage module and use it with Nitrite. Nitrite provides a simple interface StoreModule to write your own storage module."]},{"l":"StoreModule Interface","p":["To write a custom storage module, you need to implement the StoreModule interface. The interface has only one method getStore() which returns an implementation of NitriteStore interface.","Optionally, you can also implement the StoreConfig interface to provide configuration options for your storage module."]},{"l":"NitriteStore Interface","p":["The NitriteStore is the storage abstraction layer for Nitrite. It provides the basic operations required by Nitrite to store and retrieve data. A NitriteStore is responsible for managing NitriteMap and NitriteRTree instances which are the main building blocks of database collections."]},{"l":"StoreConfig Interface","p":["The StoreConfig interface provides configuration options for your storage module. You can use this interface to provide configuration options for your storage module."]},{"l":"NitriteMap Interface","p":["The NitriteMap interface is the abstraction layer for Nitrite's key-value store. It provides the basic operations required by a collection to store and retrieve data. A NitriteMap is responsible for managing NitriteId and Document instances which are the main unit of data storage in Nitrite."]},{"l":"NitriteRTree Interface","p":["The NitriteRTree interface is the abstraction layer for Nitrite's R-Tree. It provides the basic operations required by a spatial index to store and retrieve data."]},{"l":"Example","p":["Let's write a simple storage module which stores data in a Map object. The module will be a simple in-memory storage module. The module will be configured with a Map object and will use it to store data."]},{"l":"Store Module","p":["The following code snippet shows the implementation of the storage module."]},{"l":"Store Config","p":["The following code snippet shows the implementation of the store configuration.","And the builder class for the configuration."]},{"l":"Nitrite Store","p":["The following code snippet shows the implementation of the NitriteStore interface."]},{"l":"Nitrite Map","p":["The following code snippet shows the implementation of the NitriteMap interface."]},{"l":"Nitrite RTree","p":["The following code snippet shows the implementation of the NitriteRTree interface."]}],[{"l":"Spatial Module","p":["Nitrite Spatial module provides support for spatial queries. The module uses JTS library for spatial operations."]},{"l":"Adding Spatial Module","p":["Add Spatial module to your project:"]},{"l":"Maven","p":["Add the Spatial dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the Spatial dependency to your build.gradle file:"]},{"l":"Using Spatial Module","p":["To use Spatial module, you need to load the SpatialModule while opening the database.","If Nitrite is using the default SimpleNitriteMapper, then the SpatialModule will automatically register the GeometryConverter with the mapper. If you are using your own custom mapper, then you need to register the GeometryConverter with the mapper."]},{"l":"GeometryConverter","p":["GeometryConverter is an EntityConverter which is used to convert Geometry object of JTS to Document and vice-versa. It is used to store the Geometry object in the database."]},{"l":"Using Spatial Modules with Jackson","p":["If you are using Jackson module for serialization, you need to register the GeometryModule with Jackson as well.","The GeometryModule is required to serialize the Geometry object of JTS via Jackson."]},{"l":"Spatial Index","p":["Spatial module uses R-Tree index to store the spatial data.","To create a spatial index, you need to pass the index type as SpatialIndexer.SPATIAL_INDEX while creating the index.","Spatial index is not supported on multiple fields."]},{"l":"Spatial Filter","p":["Spatial module supports several filters to query spatial data. To know more about filters, please refer to Spatial Filters."]}],[{"l":"Jackson Mapper Module","p":["Nitrite provides a Jackson mapper module to convert Java objects to Document and vice-versa. The module is useful when you don't want to use the EntityConverter interface to map Java objects to Document and vice-versa."]},{"l":"Adding Jackson Mapper Module","p":["Add the Jackson mapper module to your project:"]},{"l":"Maven","p":["Add the Jackson mapper module dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the Jackson mapper module dependency to your build.gradle file:"]},{"l":"Using Jackson Mapper Module","p":["To use Jackson mapper module, you need to load the JacksonMapperModule while opening the database."]},{"l":"Using Custom Jackson Modules","p":["If you want to register any custom Jackson module, you can do so by passing the module to JacksonMapperModule constructor.","If you want to register multiple modules, you can do so by passing an array of modules to JacksonMapperModule constructor.","And here is an example of a custom Jackson module."]},{"l":"Customizing ObjectMapper","p":["If you want to customize the ObjectMapper used by the Jackson mapper module, you can do so by extending the JacksonMapper class and overriding the getObjectMapper() method.","Now, you can use this custom mapper while building the database."]}],[{"l":"Usage","p":["Nitrite provides some additional functionalities via nitrite-support library. You can use the library to enable encryption, import/export database, and database recovery."]},{"l":"Adding nitrite-support","p":["Add the nitrite-support dependency to your project:"]},{"l":"Maven","p":["Add the nitrite-support dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite-support dependency to your build.gradle file:"]}],[{"i":"importexport","l":"Import/Export","p":["Nitrite provides import/export functionality via nitrite-support library. You can import/export your database to/from a file in JSON format. You can choose to import/export the entire database or a specific collection."]},{"l":"Exporting Database","p":["To export the entire database in JSON format, you can use the Exporter class of nitrite-support library. You can construct an instance of Exporter from an ExportOptions instance using Exporter.withOptions() method. The ExportOptions class provides various options to configure the export process.","The exportTo() method can take a File or a String or an OutputStream or a Writer as an argument. If you pass a File or a String argument, the exporter will create a FileOutputStream and write the exported data to the file. If you pass an OutputStream or a Writer argument, the exporter will write the exported data to the stream or writer.","The database must be in closed state before exporting."]},{"l":"Export Options","p":["collections- the list of collections to export. The rules for specifying the collection names are as follows:","exportData- whether to export data or not. It's an optional field, if not provided, it will be set to true.","exportIndices- whether to export indices or not. It's an optional field, if not provided, it will be set to true.","If a non-empty list is specified, only the collections in the list will be exported.","If a non-empty list is specified, only the repositories in the list will be exported.","If a non-empty map is specified, only the keyed repositories in the map will be exported.","If an empty list is specified, no collection will be exported.","If an empty list is specified, no repository will be exported.","If an empty map is specified, no keyed repository will be exported.","If null is specified, all collections will be exported.","If null is specified, all keyed repositories will be exported.","If null is specified, all repositories will be exported.","jsonFactory- the JsonFactory instance to use for export. It is used to create the JsonGenerator instance for export. It's an optional field, if not provided, a default one will be used.","keyedRepositories- the map of keyed repositories to export. The rules for specifying the keyed repository names are as follows:","nitriteFactory- the NitriteFactory instance to use for export. It is used to create the Nitrite instance for export. It's a mandatory field.","repositories- the list of repositories to export. The rules for specifying the repository names are as follows:","The ExportOptions class provides various options to configure the export process. You can set the following options:"]},{"l":"Example","p":["First create a method to create a Nitrite instance, which will be used as the nitriteFactory.","Then create the ExportOptions instance and configure it.","Then create the Exporter instance and export the database.","The test.json file will contain the exported data."]},{"l":"Importing Database","p":["To import the entire database from an exported JSON data, you can use the Importer class of nitrite-support library. You can construct an instance of Importer from an ImportOptions instance using Importer.withOptions() method. The ImportOptions class provides various options to configure the import process.","The importFrom() method can take a File or a String or an InputStream or a Reader as an argument. If you pass a File or a String argument, the importer will create a FileInputStream and read the exported data from the file. If you pass an InputStream or a Reader argument, the importer will read the exported data from the stream or reader.","The database must be in closed state before importing."]},{"l":"Import Options","p":["The ImportOptions class provides various options to configure the import process. You can set the following options:","nitriteFactory- the NitriteFactory instance to use for import. It is used to create the Nitrite instance for import. It's a mandatory field.","jsonFactory- the JsonFactory instance to use for import. It is used to create the JsonParser instance for import. It's an optional field, if not provided, a default one will be used."]},{"i":"example-1","l":"Example","p":["First create a ImportOptions instance and configure it using the createDb() method from the previous example.","Then create the Importer instance and import the database.","The new-test.db file will contain the imported data. You can open the database and use it."]}],[{"l":"Encryption","p":["Nitrite provides encryption support via nitrite-support module. You can encrypt your data using a password. Nitrite provides an Encryptor interface to encrypt and decrypt data. Nitrite also provides an AES based implementation of Encryptor interface, which uses AES/GCM/NoPadding algorithm to encrypt and decrypt data."]},{"l":"Using Encryption","p":["To use encryption, you can either use the AES implementation of Encryptor interface or you can create your own implementation of Encryptor interface."]},{"l":"Using AES Encryptor","p":["To use AES based encryption you need to use the AESEncryptor class. The class takes a password as a parameter in its constructor.","There is another constructor also which takes a password along with the algorithm, tag length, IV length, and salt length.","You can use the encryptor to encrypt and decrypt data."]},{"l":"Using Custom Encryptor","p":["If you want to use your own encryption algorithm, you can do so by implementing the Encryptor interface. The interface has two methods encrypt and decrypt. You can implement these methods to encrypt and decrypt data."]},{"l":"Field Level Encryption","p":["Nitrite provides field level encryption support. You can encrypt a field of a document using a password. Nitrite provides a StringFieldEncryptionProcessor utility class to encrypt and decrypt a field of a document. It is a Processor implementation. It uses the Encryptor interface to encrypt and decrypt data."]},{"l":"Using Field Encryption","p":["To use field encryption, you need to create an instance of StringFieldEncryptionProcessor class. The class takes either an Encryptor instance or a password as a parameter in its constructor.","If you provide the password, the class will create an instance of AESEncryptor class using the password. If you provide an Encryptor instance, the class will use the provided Encryptor instance.","You can also use the AESEncryptor class to create an instance of StringFieldEncryptionProcessor class.","The encrypted data is a base64 encoded string of the encrypted bytes."]}],[{"i":"#","p":["This guide will help you get started with Nitrite database. It will show you how to create a database, create a collection, insert documents, and query documents in Kotlin."]},{"l":"Getting Started in Kotlin","p":["Nitrite's Kotlin SDK is a wrapper around the Java SDK. It provides some Kotlin friendly extensions for some of the Java API to work with Nitrite database. The Kotlin SDK is available as a separate module named potassium-nitrite(KNO 2). In this guide, we will discuss the Kotlin specific API only. For rest of the API, please refer to the Java SDK. So it is highly recommended to go through the Java SDK guide first.","To get started with Nitrite database, you need to add the Nitrite BOM to your project. The BOM will help you to manage the dependencies. Details of the BOM can be found here.","To add the BOM to your project, follow the steps below:"]},{"l":"Add dependency","p":["To enable Kotlin support, you need to add the potassium-nitrite library to your project. It will automatically add the nitrite library as a dependency along with nitrite-spatial and nitrite-jackson-mapper libraries."]},{"l":"Maven","p":["Add the nitrite dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite dependency to your build.gradle file:","The latest released version of Nitrite can be found here."]},{"l":"Snapshot builds","p":["Snapshot builds are available from Sonatype.","To use snapshot builds, you need to add the snapshot repository to your pom.xml or build.gradle file:"]},{"i":"maven-1","l":"Maven"},{"i":"gradle-1","l":"Gradle","p":["Nitrite's Kotlin SDK is not as lean as the Java SDK. It has a lot of dependencies. If you are using Kotlin in your project, it is recommended to use the Kotlin SDK. Otherwise, you can use the Java SDK with Kotlin as well."]},{"i":"upgrade-from-3x","l":"Upgrade from 3.x","p":["If you are upgrading from 3.x, please note that there are lots of breaking changes in the API. The whole library is re-written from scratch. It is recommended to go through this guide before upgrading.","You need to use the MVStore as your storage module to upgrade from 3.x. The RocksDB module is not backward compatible.","Nitrite will try to migrate your existing database to the latest version on the provided you are using the MVStore module. If you are using the RocksDB module, you need to migrate your database manually. However, it is recommended to take a backup of your database before upgrading."]}],[{"l":"Nitrite Database","p":["Nitrite database is a serverless, embedded, and self-contained Java NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Creating a Database","p":["Nitrite database can be created in-memory or on-disk. By default, Nitrite database is created in-memory. To create a database on-disk, you need to add a storage module dependency to your project. More details about storage modules can be found here.","To create a database, you need to use nitrite() function. It is a builder function that returns an instance of Nitrite."]},{"l":"In-memory Database","p":["If you don't load any on-disk storage module, then Nitrite will create an in-memory database. The below code snippet shows how to create a database in-memory."]},{"l":"On-disk Database","p":["The below code snippet shows how to create a database on-disk."]},{"l":"MVStore Backed Database","p":["More details about MVStore configuration can be found here."]},{"l":"RocksDB Backed Database","p":["More details about RocksDB configuration can be found here."]},{"l":"Securing a Database","p":["To secure a database, you need to pass a username and password to the nitrite() function. The below code snippet shows how to secure a database.","If you are using a file-based database, then you need to use the same username and password to open the database again. Otherwise, you will get a NitriteSecurityException.","Both username and password must be provided or both must be null."]},{"l":"Registering an EntityConverter","p":["Nitrite database uses a mapper to map Kotlin/Java entities to Nitrite documents and vice-versa. By default, Nitrite uses SimpleNitriteMapper as its mapper. This mapper uses EntityConverter s to map entities to Nitrite documents and vice-versa. To register an EntityConverter, you need to call registerEntityConverter() method on Builder instance.","More details about EntityConverter can be found here."]},{"l":"Loading a Nitrite Module","p":["Nitrite database is modular in nature. It provides a set of modules to extend its functionality. To load a module, you need to call loadModule() method on Builder instance.","More details about Nitrite modules can be found here."]},{"l":"Loading a Storage Module","p":["More details about storage modules can be found here."]},{"l":"Adding Migration Steps","p":["Nitrite database supports migration from one version to another. To add a migration step, you need to call addMigration() method on Builder instance.","More details about schema migration can be found here."]},{"l":"Current Schema Version","p":["To configure the current schema version, you need to set the schemaVersion property on Builder instance.","By default, the initial schema version is set to 1."]},{"l":"Field Separator Character","p":["Nitrite database uses . as the field separator character. It is used to separate nested fields in a document. For example, if you have a document like below:","Then you can access the firstName field like below:","And you can access the street field like below:","To configure the field separator character, you need to set the fieldSeparator property on Builder instance.","By default, the field separator character is set to .."]}],[{"l":"Document","p":["Document is the basic unit of data in Nitrite database. It is a JSON like field-value pairs. The field is always a String and value can be anything including null. Document is schema-less, which means you can store any kind of data in a document.","Nitrite document supports nested document. That means, a value of a field can be another document. This allows you to create complex data structure.","More details on document can be found here."]},{"l":"Kotlin API for Document","p":["Potassium Nitrite provides a set of extension functions to make document manipulation easier."]},{"l":"Create a Document","p":["To create a document, you can use the documentOf function. It takes a vararg of PairString, Any? and returns a Document.","To create a nested document, you can use the documentOf function recursively.","To create an empty document, you can use the emptyDocument function."]},{"l":"Get a Field Value","p":["To get a field value from a document, you can use the index operator [] on the document. It takes a String as the field name and returns the value of the field."]},{"l":"Checking If a Document is Empty","p":["To check if a document is empty, you can use the isEmpty function. It takes no argument and returns a Boolean.","Conversely, to check if a document is not empty, you can use the isNotEmpty function. It takes no argument and returns a Boolean."]}],[{"l":"Nitrite Collection","p":["NitriteCollection represents a named document collection stored in a Nitrite database. It persists documents in a Nitrite database. It is similar to a table in relational database or a collection in MongoDB.","More details on collection can be found here."]},{"l":"Kotlin API for NitriteCollection","p":["Potassium Nitrite provides a higher-order function to make collection manipulation easier."]}],[{"l":"Object Repository","p":["ObjectRepository provides a simple and type-safe API for storing and retrieving Kotlin/Java objects in a Nitrite database. It is built on top of NitriteCollection and provides a similar API for CRUD operations. It also supports indexing and querying. It also supports event based notification on object changes.","More details on repository can be found here."]},{"l":"Kotlin API for ObjectRepository","p":["Potassium Nitrite provides some higher-order functions to make repository manipulation easier."]},{"l":"Creating a Repository with Class Type","p":["You can create a ObjectRepository by passing a class type to getRepository() method."]},{"l":"Creating a Repository with Class Type and Key","p":["You can create a keyed ObjectRepository by passing a class type and a key to getRepository() method.","One typical use case of this keyed repository is to create a repository for each user in a multi-user application. The key can be the user name or user id. This will ensure that each user will have a separate repository for storing objects."]},{"l":"Creating a Repository with EntityDecorator","p":["A ObjectRepository can be created using EntityDecorator. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"Creating a Repository with EntityDecorator and Key","p":["A keyed ObjectRepository can be created using EntityDecorator and a key. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"NitriteMapper","p":["Nitrite provides a mapper interface called NitriteMapper. It is used to map Java objects to Nitrite documents and vice-versa. More details on NitriteMapper can be found here.","Apart from the SimpleNitriteMapper, Potassium Nitrite also provides two additional mappers:","KNO2JacksonMapper","KotlinXSerializationMapper"]},{"l":"Jackson Mapper","p":["Potassium Nitrite extends the JacksonMapper to provide KNO2JacksonMapper. This class overrides the getObjectMapper() method to register some Kotlin specific Jackson modules as follows:","KotlinModule","JavaTimeModule","Jdk8Module","GeometryModule","It also disables the SerializationFeature.WRITE_DATES_AS_TIMESTAMPS feature. The constructor of KNO2JacksonMapper takes a vararg of com.fasterxml.jackson.databind.Module to register additional Jackson modules.","To use the KNO2JacksonMapper instead of the default SimpleNitriteMapper you need to load it while opening the database."]},{"l":"KotlinX Serialization Mapper","p":["Potassium Nitrite also provides a KotlinX Serialization based mapper called KotlinXSerializationMapper. KotlinX Serialization is used to convert Java/Kotlin objects to Document and vice-versa.","To use the KotlinXSerializationMapper instead of the default SimpleNitriteMapper you need to load it while opening the database."]}],[{"l":"Filters","p":["Filters are used to specify the criteria used to select documents from a collection or repository. It provides a way to specify conditions that the documents must meet to be included in the result set. Filters are used in conjunction with the find method. The find method returns all documents in a collection that match the specified filtering criteria.","More details on filters can be found here."]},{"l":"Kotlin API for Filters","p":["Potassium Nitrite provides a set of infix functions to make filter usage more like operators. It also provides a set of extension functions for KProperty so that you can use property name instead of string in case of entity class."]},{"l":"Comparison Operators","p":["Comparison operators are used to compare two expressions. More details on comparison operators can be found here."]},{"l":"Equal To","p":["To check if a field value is equal to a value, you can use the eq function.","Similarly, you can use the eq function with KProperty.","More details on eq function can be found here."]},{"l":"Not Equal To","p":["To check if a field value is not equal to a value, you can use the notEq function.","Similarly, you can use the notEq function with KProperty.","More details on notEq function can be found here."]},{"l":"Greater Than","p":["To check if a field value is greater than a value, you can use the gt function.","Similarly, you can use the gt function with KProperty.","More details on gt function can be found here."]},{"l":"Greater Than or Equal To","p":["To check if a field value is greater than or equal to a value, you can use the gte function.","Similarly, you can use the gte function with KProperty.","More details on gte function can be found here."]},{"l":"Less Than","p":["To check if a field value is less than a value, you can use the lt function.","Similarly, you can use the lt function with KProperty.","More details on lt function can be found here."]},{"l":"Less Than or Equal To","p":["To check if a field value is less than or equal to a value, you can use the lte function.","Similarly, you can use the lte function with KProperty.","More details on lte function can be found here."]},{"l":"Within","p":["To check if a field value is in a list of values, you can use the within function.","Similarly, you can use the within function with KProperty.","You can also use it with range.","More details on within function can be found here."]},{"l":"Not Within","p":["To check if a field value is not in a list of values, you can use the notWithin function.","Similarly, you can use the notWithin function with KProperty.","You can also use it with range.","More details on notWithin function can be found here."]},{"l":"Between","p":["To check if a field value is between two values, you can use the between function. More details on between function can be found here."]},{"l":"Logical Filters","p":["Logical operators are used to combine two or more expressions. More details on logical operators can be found here."]},{"l":"And","p":["To combine two or more expressions with AND operator, you can use the and function.","Similarly, you can use the and function with KProperty.","More details on and function can be found here."]},{"l":"Or","p":["To combine two or more expressions with OR operator, you can use the or function.","Similarly, you can use the or function with KProperty.","More details on or function can be found here."]},{"l":"Array Filters","p":["Array filters are used to match documents based on the values in an array field. More details on array filters can be found here."]},{"l":"Element Match","p":["To check if an array field contains at least one element that matches the specified filter, you can use the elemMatch function.","Similarly, you can use the elemMatch function with KProperty.","More details on elemMatch function can be found here."]},{"l":"Evaluation Filters","p":["Evaluation filters are used to match documents based on evaluating the value of any field in a document. More details on evaluation filters can be found here."]},{"l":"Regex","p":["To check if a field value matches a regular expression, you can use the regex function.","Similarly, you can use the regex function with KProperty.","More details on regex function can be found here."]},{"l":"Text","p":["The text filter is used to match documents which contain a specified full-text search expression.","Similarly, you can use the text function with KProperty.","More details on text function can be found here."]},{"l":"Spatial Filters","p":["Spatial filters are used to match documents based on their geometric shape. More details on spatial filters can be found here."]},{"l":"Near","p":["To check if a field value is near to a point, you can use the near function.","Similarly, you can use the near function with KProperty.","More details on near function can be found here."]},{"i":"within-1","l":"Within","p":["To check if a field value is within a specified shape, you can use the within function.","Similarly, you can use the within function with KProperty.","More details on within function can be found here."]},{"l":"Intersects","p":["The intersects filter is used to match documents where the value of the spatial field intersects the specified shape.","Similarly, you can use the intersects function with KProperty.","More details on intersects function can be found here."]}],[{"l":"Transaction","p":["Nitrite supports transactional operations on its collections and repositories. A transaction can be committed or rolled back. Once a transaction is committed, all the changes are persisted to the disk. If a transaction is rolled back, all the changes are discarded.","More information about Nitrite transactions can be found here."]},{"l":"Kotlin API for Transaction","p":["Potassium Nitrite provides a set of builder functions for Session and Transaction to make transaction usage more like natural to Kotlin."]},{"l":"Session","p":["A session represents a transactional context for a Nitrite database. Session is used to create a new transaction. More details on session can be found here."]},{"l":"Kotlin API for Session","p":["To create a new session, you can use the session() extension function on Nitrite.","Session will be automatically closed once the block is executed."]},{"l":"Transaction","p":["A transaction is a single logical unit of work which accesses and possibly modifies the contents of a database. Transactions access data using read and write operations. More details on transaction can be found here."]},{"i":"kotlin-api-for-transaction-1","l":"Kotlin API for Transaction","p":["To start a transaction, you can use the tx() extension function on Session.","Transaction will be automatically closed once the block is executed."]}],[{"l":"Potassium Nitrite Module","p":["Nitrite is a modular database engine, so is Potassium Nitrite. All Nitrite modules are compatible with Potassium Nitrite as well. More details about Nitrite modules can be found here.","Potassium Nitrite provides a single module KNO2Module to load all plugins it provides. You can load the module while opening the database.","This module loads the following plugins:","KNO2JacksonMapper- A Jackson based mapper for Potassium Nitrite.","SpatialIndexer- A spatial index plugin for Nitrite.","Visit the respective pages to know more about the plugins."]}],[{"i":"#","p":["This guide will help you get started with Nitrite database. It will show you how to create a database, create a collection, insert documents, and query documents in Flutter."]},{"l":"Getting Started in Flutter","p":["Nitrite is a pure Dart database. It does not depend on any native library. So it can be used in any platform where Dart is supported. It is a server-less embedded database ideal for desktop, mobile, or web applications. It is written in pure Dart and runs in Flutter, Dart VM, and the browser.","To get started with Nitrite database, you need to add the dependency to your pubspec.yaml file."]},{"l":"Add dependency","p":["Add Nitrite dependency to your project:","The latest released version of Nitrite can be found here.","To add the nitrite code generator to your project, add the following to your pubspec.yaml file:","More details about the code generator can be found here.","To add the hive adapter to your project, add the following to your pubspec.yaml file:","More details about the hive adapter can be found here.","Nitrite is null safe. So you can use it in your null safe project."]}],[{"l":"Database","p":["Nitrite database is a serverless, embedded, and self-contained database for Flutter. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Creating a Database","p":["Nitrite database can be created in-memory or on-disk. By default, Nitrite database is created in-memory. To create a database on-disk, you need to add a storage module dependency to your project. More details about storage modules can be found here.","To create a database, you need to use NitriteBuilder class. To get an instance of NitriteBuilder, you need to call builder() method on Nitrite class."]},{"l":"In-memory Database","p":["If you don't load any on-disk storage module, then Nitrite will create an in-memory database. The below code snippet shows how to create a database in-memory."]},{"l":"On-disk Database","p":["The below code snippet shows how to create a database on-disk."]},{"l":"Hive Backed Database","p":["More details about Hive configuration can be found here."]},{"l":"NitriteBuilder","p":["NitriteBuilder is the builder class for Nitrite database. It provides methods to configure and create a Nitrite database instance."]},{"l":"Open or Create a Database","p":["To open or create a database, you need to call openOrCreate() method on NitriteBuilder instance. This method returns a FutureNitrite instance.","If no StoreModule is configured, then Nitrite will create an in-memory database. If a StoreModule is configured, then Nitrite will create an on-disk database. If the database file does not exist, then Nitrite will create a new database file. If the database file exists, then Nitrite will open the database file."]},{"l":"Securing a Database","p":["To secure a database, you need to call openOrCreate() method with username and password on NitriteBuilder instance. This method returns a FutureNitrite instance with the given username and password.","If you are using a file-based database, then you need to use the same username and password to open the database again. Otherwise, you will get a NitriteSecurityException.","Both username and password must be provided or both must be null."]},{"l":"Registering an EntityConverter","p":["Nitrite database uses a mapper to map a Dart object to a document and vice versa. By default, Nitrite uses SimpleNitriteMapper as its mapper. This mapper uses EntityConverter s to map a Dart object to a document and vice versa. To register an EntityConverter, you need to call registerEntityConverter() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More details about EntityConverter can be found here."]},{"l":"Loading a Module","p":["Nitrite database is modular in nature. It provides various modules to extend its functionality. To load a module, you need to call loadModule() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance."]},{"l":"Loading a Storage Module","p":["More on the Nitrite's module system can be found here."]},{"l":"Adding Migration Steps","p":["Nitrite database supports schema migration. To configure a migration step, you need to call addMigrations() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More on the schema migration can be found here."]},{"l":"Current Schema Version","p":["To get the current schema version of a database, you need to call schemaVersion() method on NitriteBuilder instance. This method returns the current schema version of the database.","By default, the initial schema version is set to 1."]},{"l":"Field Separator Character","p":["To configure the field separator character, you need to call fieldSeparator() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","It is used to separate field names in a nested document. For example, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax.","The default field separator character is set to .."]}],[{"l":"Document","p":["Document is the basic unit of data in Nitrite database. It is a JSON like field-value pairs. The field is always a String and value can be anything including null. Document is schema-less, which means you can store any kind of data in a document.","Nitrite document supports nested document. That means, a value of a field can be another document. This allows you to create complex data structure."]},{"l":"Document Structure","p":["Nitrite document has the following structure."]},{"l":"Document Field","p":["Document field is always a String. It can be any valid string. The field cannot be null or empty string.","Below fields are reserved and cannot be used as key in a document.","_id: The unique identifier of a document. This field is auto-generated by Nitrite database during insertion.","_revision: The revision number of a document. This field is auto-generated by Nitrite database during insertion and update.","_source: The source collection name of a document.","_modified: The last modified timestamp of a document. This field is auto-generated by Nitrite database during insertion and update."]},{"l":"Document Value","p":["Document value can be any valid Dart object. It can be null or any of the below types.","String","int","double","bool","List","Map","Set","DateTime","NitriteId","Document"]},{"l":"Document Identifier","p":["It is a unique identifier of a document. It is auto-generated by Nitrite database during insertion. It is a NitriteId and is stored as a String in the document."]},{"l":"NitriteId","p":["NitriteId is a unique identifier across the Nitrite database. Each document in a nitrite collection is associated with a NitriteId.","During insertion if a unique String value representing a integer is supplied in the _id field of the document, then the value of the _id field will be used to generate the NitriteId. Otherwise, a new NitriteId will be generated and will be used in the _id field of the document.","The value of the NitriteId is a String representation of a 64-bit integer. The id generation is based on Twitter Snowflake algorithm. The id is composed of:","41 bits for time in milliseconds","10 bits for a machine id","12 bits for a sequence number","1 unused sign bit","The id is not guaranteed to be monotonically increasing. The id is sortable and the timestamp is stored in the id itself."]},{"l":"Retrieving a NitriteId from a Document","p":["The id can be retrieved from a document using Document.id getter. If the document does not have an id, then it will create a new NitriteId and will set it in the document and will return the id. If the document already has an id, then it will return the id."]},{"l":"Field Separator","p":["To access a field of a nested document, or an element of an array field, you need to use the field separator.","Field separator is configurable. You can change the field separator character by calling NitriteBuilder.fieldSeparator() method.","Nitrite uses . as field separator by default."]},{"l":"Nested Document","p":["To specify or access a field of a nested document, you need to use the field separator character. That means, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax."]},{"l":"Array Field","p":["To specify or access an element of an array field, you need to use the index of the element. For example, if a document has a field phone which is an array, then the first element of the array can be accessed using phone.0 syntax."]},{"l":"Creating a Document","p":["To create a document, you need to use createDocument() function."]},{"l":"Creating an Empty Document"},{"l":"Creating a Document with Initial Field-value Pair"},{"l":"Creating a Document with a Map"},{"l":"Updating a Document","p":["To update a document, you need to use Document.put() method. This method takes two parameters, the field name and the value. If the field already exists in the document, then the value will be updated. If the field does not exist, then it will be created.","You can also use the [] operator to update a document."]},{"l":"Retrieving a Value from Document","p":["To retrieve a value from document, you need to use Document.get() method. This method takes one parameter, the field name. If the field exists in the document, then the value will be returned. If the field does not exist, then it will return null.","You can also use the [] operator to retrieve a value from a document.","To retrieve a value from a nested document, use the field separator character.","To retrieve an element from an array field, use the index of the element."]},{"l":"Removing a Field from Document","p":["To remove a field from document, you need to use Document.remove() method. This method takes one parameter, the field name. If the field exists in the document, then it will be removed. If the field does not exist, then it will do nothing.","To remove a field from a nested document, use the field separator character.","To remove an element from an array field, use the index of the element."]},{"l":"Checking If a Field Exists in Document","p":["To check if a field exists in a document, you need to use Document.containsKey() method. This method takes one parameter, the field name. If the field exists in the document, then it will return true. If the field does not exist, then it will return false.","To check if a field exists in a nested document, use the field separator character.","It cannot check if an element exists in an array field."]}],[{"l":"Introduction","p":["NitriteCollection represents a named document collection stored in a Nitrite database. It persists documents in a Nitrite database. It is similar to a table in relational database or a collection in MongoDB.","Each document in a collection is associated with a unique NitriteId. It exposes a set of methods to perform CRUD operations on documents. It also supports indexing and querying. It also supports event based notification on document changes."]},{"l":"Creating a Collection","p":["A NitriteCollection can be created using Nitrite class. You need to call getCollection() method on Nitrite class to get an instance of a FutureNitriteCollection.","If the collection does not exist, then it will be created automatically. If a collection with the same name already exists, then it will return the existing collection."]},{"l":"Limitations on Collection Name","p":["A collection name cannot be null or empty string. It cannot contains any of the following characters:","|(pipe)",":(colon)","+(plus)","The name also cannot be any of the following reserved words:","$nitrite_users","$nitrite_index_meta","$nitrite_index","$nitrite_meta_map","$nitrite_store_info","$nitrite_catalog"]}],[{"l":"Write Operations"},{"l":"Inserting Documents","p":["Documents can be inserted into a collection using insert() or insertMany() methods. It takes one or multiple Document objects as input parameter respectively. It returns a FutureWriteResult object.","If the document has a NitriteId already in it's _id field, then it will be used as a unique key to identify the document in the collection. Otherwise, a new NitriteId will be generated and inserted into the document.","If any of the field is already indexed in the collection, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.insert event."]},{"l":"Inserting a Single Document"},{"l":"Inserting Multiple Documents"},{"l":"Error Scenarios","p":["If the document contains invalid value in it's _id field, then it will throw a InvalidIdException.","If there is another document with the same _id value in the collection, then it will throw a UniqueConstraintException.","If a field of the document is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["WriteResult contains the result of a write operation. It contains the following information:","Number of documents affected by the write operation. You can get this value using getAffectedCount() method.","List of NitriteId of the documents affected by the write operation. The WriteResults implements IterableNitriteId interface. So you can iterate over the WriteResult to get the NitriteId of the documents affected by the write operation."]},{"l":"Updating Documents","p":["Documents can be updated using any of the following methods:","updateOne()- Updates a single document.","update()- Update the filtered documents in the collection.","All update methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.update event."]},{"l":"Updating a Single Document","p":["You can update a single document using updateOne() method. It takes a Document object as input parameter. It returns a FutureWriteResult object. The document must contain a valid NitriteId in it's _id field.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Document","p":["You can also upsert a single document using updateOne() method. Along with the document parameter, you need to pass a named parameter insertIfAbsent with value true. If the document does not exist in the collection, then it will be inserted. Otherwise, it will be updated. The default value of insertIfAbsent is false."]},{"l":"Updating Using a Filter","p":["You can update multiple documents using a filter. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It returns a FutureWriteResult object."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It takes a UpdateOptions object as the optional third input parameter. It returns a FutureWriteResult object."]},{"l":"UpdateOptions","p":["UpdateOptions is a class that contains several options for update operation. It has the following options:","insertIfAbsent: If this option is true, then it will insert the document if it does not exist in the collection. Otherwise, it will update the document if it exists in the collection.","justOnce: If this option is true, then it will update only the first document matched by the filter. Otherwise, it will update all the documents matched by the filter."]},{"l":"Removing Documents","p":["Documents can be removed from a collection using any of the following methods:","removeOne()- Removes a single document.","remove()- Removes the filtered documents from the collection.","All remove methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.remove event."]},{"l":"Removing a Single Document","p":["You can remove a single document using removeOne() method. It takes a Document object as input parameter. It returns a FutureWriteResult object. The document must contain a valid NitriteId in it's _id field.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple documents using a filter. It takes a Filter object as the input parameter. It returns a FutureWriteResult object."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a named parameter justOne with value true or false. If the value is true, then it will remove only the first document matched by the filter. Otherwise, it will remove all the documents matched by the filter. The default value of justOne is false. It returns a FutureWriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["You can search documents in a collection using find() method. There are several ways of using find() method using a filter or find options or both. You can also search a document using it's NitriteId."]},{"l":"Filters","p":["Nitrite uses filters to find documents in a collection. A filter is a simple expression which evaluates to true or false. More information about filters can be found here."]},{"l":"Find All Documents","p":["You can find all documents in a collection by calling find(). It returns a DocumentCursor object."]},{"l":"Finding a Document Using NitriteId","p":["You can find a document using it's NitriteId by calling getById(). It takes a NitriteId as input parameter. It returns a FutureDocument? object if the document is found. Otherwise, it returns null."]},{"l":"Finding a Document Using a Filter","p":["You can find a document using a filter. It takes a Filter object as input parameter. It returns a DocumentCursor object.","If there is an index on the field specified in the filter, this operation will use the index to find the document. Otherwise, it will scan the entire collection to find the document."]},{"l":"Finding a Document Using a Filter and Options","p":["You can find a document 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 DocumentCursor object."]},{"l":"FindOptions","p":["FindOptions is a class that contains several options for find operation. It has the following options:","limit: It specifies the maximum number of documents to be returned by the find operation.","skip: It specifies the number of documents to be skipped from the beginning of the result set.","orderBy: It specifies a collection of fields to be sorted by, along with sort order for each field. The sort order can be SortOrder.ascending or SortOrder.descending.","distinct: It specifies if the find operation should return distinct documents. If this option is true, then it will return only the distinct documents. Otherwise, it will return all the documents matched by the filter."]},{"l":"DocumentCursor","p":["DocumentCursor represents a result set of a find operation. It provides methods to iterate over the result of a find operation and retrieve the documents. It also provides methods like projection, join etc. to get the desired result."]},{"l":"Iterating Over Documents","p":["The DocumentCursor extends StreamDocument. So, you can iterate over the documents using await for loop.","A DocumentCursor is a stream of document. It does not load all the documents in memory at once. It loads the documents in memory as needed. So, it is memory efficient."]},{"l":"Getting the Documents","p":["You can get the documents from a DocumentCursor using toList() method. It returns a FutureListDocument object."]},{"l":"Getting the First Document","p":["You can get the first document from a DocumentCursor using first getter. It returns a FutureDocument? object."]},{"l":"Getting the Size of the Result Set","p":["You can get the size of the result set from a DocumentCursor using length getter. It returns a Futureint object."]},{"l":"Projection","p":["You can project a field or a set of fields from a DocumentCursor using project() method. It takes a Document as input parameter. It returns a StreamDocument object.","The document must contain only the fields that needs to be projected. The field values must be null or a nested document. The condition holds true for nested documents as well.","Let's say you have a document like this:","And you want to project only lastName and address.street fields. Then you can do it like this:","The result set will contain only lastName and address.street fields."]},{"l":"Join","p":["You can join two DocumentCursor using leftJoin() method. It takes another DocumentCursor as input parameter along with a Lookup object. It returns a StreamDocument object.","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 collections users and orders. The users collection contains the following documents:","And the orders collection contains the following documents:","And you want to join these two collections on userId field. Then you can do it like this:","The result set will contain the following documents:"]},{"l":"FindPlan","p":["FindPlan is a class that contains the execution plan of a find operation. It has the following properties:","byIdFilter: It contains the filter for finding a document using NitriteId.","indexScanFilter: It contains the filter for finding a document using index.","collectionScanFilter: It contains the filter for finding a document using full scan.","indexDescriptor: It contains the index descriptor for finding a document using index.","indexScanOrder: It contains the sort order for finding a document using index.","blockingSortOrder: It contains the sort order for finding a document using full scan.","skip: It contains the number of documents to be skipped from the beginning of the result set.","limit: It contains the maximum number of documents to be returned by the find operation.","distinct: It specifies if the find operation returns distinct documents.","subPlans: It contains the sub plans for finding a document using or filter.","You can get the execution plan of a find operation using findPlan getter. It returns a FutureFindPlan object."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a collection. It supports indexing on a single field or multiple fields. It also supports full-text indexing."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in a document. It is useful when you want to search text content in a document. It is also useful when you want to search text content in a document in a language other than English.","Document's _id field is always indexed.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. You need to implement NitriteIndexer interface to create your own custom index. NitriteIndexer is a NitritePlugin, so you need to register it using loadModule() method while opening a database. During index creation you need to pass the type of the custom index in IndexOptions object.","One of such custom index implementation can be found in spatial module. It provides spatial indexing on a collection. More on spatial indexing can be found here."]},{"l":"Creating an Index","p":["You can create an index on a collection using createIndex() method. There are several overloaded version of createIndex() method. You can create an index on a single field or multiple fields."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.nonUnique in IndexOptions object and the name of the fields on which the index will be created as input parameters."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field by passing the index type as IndexType.fullText in IndexOptions object and the name of the fields on which the index will be created as input parameters.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Array Field","p":["Nitrite supports creating index on array field. It will create index on each element of the array. For example, if you have a document like this:","You can create index on phones field like this:"]},{"l":"Creating Index on Nested Field","p":["You can create index on nested field. For example, if you have a document like this:","You can create index on street field like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index on a collection using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index on a collection using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes on a collection using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes on a collection using listIndices() method. It returns a FutureCollection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a simple class which contains the following information about an index:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists on a collection using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the collection on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Collection","p":["You can get the size of a collection using size getter. It returns a future of the number of documents in the collection."]},{"l":"Clearing a Collection","p":["You can clear all the documents from a collection using clear() method. It removes all the documents from the collection and index entries from the indexes. It does not drop the collection."]},{"l":"Dropping a Collection","p":["You can drop a collection using drop() method. It removes all the documents from the collection and index entries from the indexes. It also drops all the indexes associated with the collection. It also removes the collection from the database.","You can call isDropped getter to check if the collection is dropped or not.","Any further operation on a dropped collection will throw NitriteIOException."]},{"l":"Closing a Collection","p":["You can close a collection using close() method. Any further operation on a closed collection will throw NitriteIOException.","After closing a collection, you must re-open it via Nitrite.getCollection() method to perform any operation on it.","You can call isOpen getter to check if the collection is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a collection to get notified on document changes. The event listener must implement CollectionEventListener interface. It will receive CollectionEventInfo whenever a document is inserted, updated or removed from the collection.","You can also remove an event listener from a collection."]},{"l":"CollectionEventInfo","p":["CollectionEventInfo contains the following information:","item- the document which is inserted, updated or removed.","originator- the name of the collection on which the event is fired.","eventType- the type of the event. It can be any of the following:","EventType.insert","EventType.update","EventType.remove","EventType.indexStart","EventType.indexEnd","timestamp- the timestamp of the event."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a collection.","You can get/set attributes on a collection. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processors are used to process documents before writing them into or after reading them from a collection.","Processors are useful when you want to add some additional information in a document or transform any field before inserting or updating it in a collection. Processors are also useful when you want to validate a document before inserting or updating it in a collection.","Processors are registered on a collection. A collection can have multiple processors. Processors are executed in the order they are registered."]},{"l":"Registering a Processor","p":["You can register a processor on a collection using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a collection and decrypt a field after reading it from a collection.","More on this is described in Support."]}],[{"l":"Introduction","p":["ObjectRepository provides a simple and type-safe API for storing and retrieving Dart objects in a Nitrite database. It is built on top of NitriteCollection and provides a similar API for CRUD operations. It also supports indexing and querying. It also supports event based notification on object changes."]},{"l":"Creating a Repository","p":["An ObjectRepository can be created using Nitrite class. You need to call getRepository() method on Nitrite class to get an instance of an ObjectRepository. If the repository does not exist, then it will be created automatically. If a repository with the same name already exists, then it will return the existing repository.","There are several options available to create a repository. You can pass a class type or an EntityDecorator along with an optional string key to create a repository."]},{"l":"Creating a Repository with Class Type","p":["You can create a ObjectRepository by passing a class type to getRepository() method."]},{"l":"Creating a Repository with Class Type and Key","p":["You can create a keyed ObjectRepository by passing a class type and a key to getRepository() method.","One typical use case of this keyed repository is to create a repository for each user in a multi-user application. The key can be the user name or user id. This will ensure that each user will have a separate repository for storing objects."]},{"l":"Creating a Repository with EntityDecorator","p":["A ObjectRepository can be created using EntityDecorator. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"Creating a Repository with EntityDecorator and Key","p":["A keyed ObjectRepository can be created using EntityDecorator and a key. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]}],[{"l":"Code Generator","p":["Nitrite provides Dart build system builders to extract metadata and generate code for entity classes which is used by ObjectRepository. The builders generate code when they find a class annotated with some Nitrite specific annotations. The generated code is written to a file that is named after the source file, but with .no2.dart extension.","Flutter doesn't support reflection, so the generated code is used to extract metadata and generate code for entity classes.","There are two generators available:","Entity Generator- Extracts metadata from classes annotated with @Entity and generates code for entity classes.","Converter Generator- Scans the classes annotated with @Convertable and generates the code to convert the Dart classes to Nitrite documents and vice-versa.","Both of these generators are available in the nitrite_generator package."]},{"l":"Setup","p":["Add the following to your pubspec.yaml:","Once you have added the annotations to your code, you can run the generator using the build_runner command-line tool:"]},{"l":"Annotations for Entity Generator","p":["The following annotations are used by the entity generator:","@Entity- Marks a class as an entity class.","@Id- Marks a field as the primary key of the entity.","@Index- Provides index information for entity fields.","More on each of these annotations is here."]},{"l":"Annotations for Converter Generator","p":["The following annotations are used by the converter generator:","@Convertable- Generates the EntityConverter for the class.","@DocumentKey- Specifies the name of the field in the document.","@IgnoredKey- Marks a field as ignored while converting to document.","More on each of these annotations is here."]},{"l":"Examples","p":["Consider a book entity class and it's generated code:"]},{"l":"Limitations","p":["There are certain limitations of each of the generators as described below:"]},{"l":"Entity Generator","p":["@Entity annotation can only be used on a class.","@Id annotation can only be used on a field and once per class.","@Id field should be one of the following data types:","num","int","double","String","Runes","bool","DateTime","Duration","NitriteId","A class in case of embedded id.","@Id field should not be static or synthetic."]},{"l":"Converter Generator","p":["@Convertable annotation can only be used on a class and not on an abstract class or mixin.","@Convertable can only be used on a class which has at least one public constructor which is either a default constructor or one with all the parameters named or optional. Examples are given below.","@DocumentKey annotation can not be used on a private/static/synthetic field.","@DocumentKey, @IgnoredKey annotation can only be used on a field or property.","@IgnoredKey annotation can not be used on a field with the same name as a non-null required named parameter in the constructor.","A class with a constructor having all named parameters (optional/required) should have all the fields' names same as the parameter names.","A class with a constructor having all positional optional parameters should not have any final field.","A getter must be defined for corresponding setter or vice-versa.","dynamic type is not supported.","Function types are not supported.","If any of the above limitations are not met, then the generator will throw an exception and the build will fail.","Nested collection is not supported.","Never type is not supported.","Symbol type is not supported.","There are certain limitations on the fields and its data types:","Void type is not supported."]}],[{"l":"Entity","p":["An entity is a Dart object that can be stored in a collection. An entity can be a simple class with a few fields or a complex class with nested objects. Every entity in an ObjectRepository is actually converted to a Document before storing in the underlying NitriteCollection. When an entity is converted to a Document, the fields of the entity are mapped to the fields of the Document. While retrieving an entity from the ObjectRepository, the Document is converted back to the entity.","Nitrite uses a NitriteMapper implementation to convert an entity to a Document and vice versa. By default, Nitrite uses an EntityConverter based implementation of NitriteMapper to convert an entity to a Document. You can also provide your own implementation of NitriteMapper to convert an entity to a Document.","More on NitriteMapper can be found here."]},{"l":"Annotations","p":["Nitrite uses annotations to define an entity. There are several annotations available to define an entity. These annotations are:","@Entity","@Id","@Index","Flutter does not support reflection. So, Nitrite uses code generators to process these annotations and generates the metadata for an entity. The entity generator generates a mixin for an entity class in a separate file that is named after the source file, but with .no2.dart extension.","The name of the mixin is like - _$+ ClassName+ EntityMixin. For example, if the entity class name is Person, the mixin name will be _$PersonEntityMixin. The generated mixin also implements NitriteEntity interface which defines few getters to access the metadata of the entity. You need to add this mixin to your entity class to make it a Nitrite entity.","The entity generator is a separate package and more on the entity generator can be found here."]},{"i":"entity","l":"@Entity","p":["The @Entity annotation marks a class as an entity class. The annotation has the following properties:","name- The name of the collection to which the entity belongs. If not specified, the name of the class is used as the collection name.","indices- An array of @Index annotations. The indices are created on the fields specified in the @Index annotation.","The above code generates the following code in book.no2.dart:","Now you can use the generated mixin in your entity class:"]},{"i":"id","l":"@Id","p":["The @Id annotation marks a field as the unique identifier of the entity. It is a field level annotation and takes optional fieldName parameter. The fieldName parameter is used to specify the name of the field in the document. If the fieldName parameter is not specified, then the name of the field in the class will be used as the name of the field in the document.","The above code generates the following code in book.no2.dart:"]},{"l":"Embedded Id","p":["Nitrite also supports embedded id. The embedded id is used when the entity has a composite primary key. The @Id annotation can also be used to mark a field as an embedded id. In case of embedded id, the field should be marked with @Id annotation and the fieldName and embeddedFields parameters should be specified. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","The above code generates the following code in book.no2.dart:","The above @Id annotation will create a unique compound index on the fields - book_id.isbn and book_id.title."]},{"l":"Data Type","p":["The data type of the field marked with @Id annotation should be one of the following:","num","int","double","String","Runes","bool","DateTime","Duration","NitriteId","In case of embedded id, the data type of the field marked with @Id annotation should be a class."]},{"i":"index","l":"@Index","p":["@Index annotation is used to declare an index on an entity field. It is a class level annotation and takes mandatory fields parameter and optional type parameter. The fields parameter is used to specify the names of the fields in the document to be indexed. The type parameter is used to specify the type of the index. If the type parameter is not specified, then the type of the index will be IndexType.unique.","The above code generates the following code in book.no2.dart:","The above @Index annotations will create the following indices:","tags- Non-unique simple index","description- Full-text index","price and publisher- Unique compound index","@Index annotation can be used on super class as well. When the entity class extends a super class, the @Index annotations of the super class are also processed by the entity generator."]},{"l":"EntityDecorator","p":["EntityDecorator is used to add metadata to an entity. If you cannot modify the entity class to add annotations, then you can use EntityDecorator to add metadata to an entity. You can use EntityDecorator to add id, indices and collection name for an entity.","While creating or opening a repository, you can pass an instance of EntityDecorator to the getRepository() method on Nitrite class. Nitrite will extract the metadata from the EntityDecorator instance and use it to create the repository.","To write an EntityDecorator for an entity, you need to implement the EntityDecorator interface. Let's take an example of a Product entity.","The Product entity has an embedded id ProductId and two indices on a nested object Manufacturer. To write an EntityDecorator for the Product entity with collection name 'products', you need to implement the EntityDecorator interface as follows.","which is equivalent to the following entity class when code generator is used:"]},{"l":"EntityId","p":["EntityId is used to specify the id field of an entity. It takes mandatory fieldName parameter and optional embeddedFields parameter in case of embedded id. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","Here productId is the name of the field in the document and uniqueId and productCode are the names of the fields in the embedded object. This will create a unique compound index on the fields - productId.uniqueId and productId.productCode."]},{"l":"EntityIndex","p":["EntityIndex is used to specify the indices on an entity. It takes mandatory type parameter and fields parameter. The type parameter is used to specify the type of the index. The fields parameter is used to specify the name of the fields in the document to be indexed.","Here manufacturer.name is the name of the field in the document and productName and manufacturer.uniqueId are the names of the fields in the document. This will create a non-unique index on the field manufacturer.name and a unique compound index on the fields - productName and manufacturer.uniqueId."]},{"l":"Entity Name","p":["Entity name is used to specify the name of the collection in which the entity will be stored. It is a string value and can be specified using entityName getter.","Here products is the name of the NitriteCollection in which the product document will be stored."]}],[{"l":"NitriteMapper","p":["NitriteMapper is a simple and lightweight object mapper which can be used to map Dart objects to Nitrite documents and vice-versa. Nitrite uses a NitriteMapper implementation to map Dart entities to Nitrite documents and vice-versa while storing and retrieving objects from an ObjectRepository."]},{"l":"SimpleNitriteMapper","p":["Nitrite provides a default NitriteMapper implementation called SimpleNitriteMapper. This is a simple and lightweight mapper which uses EntityConverter to map a Dart object to Nitrite documents and vice-versa. This mapper is suitable for most of the use cases."]},{"l":"EntityConverter","p":["EntityConverter is a simple interface which provides methods to convert a Dart object to Nitrite document and vice-versa. For each Dart class, you need to provide an implementation of EntityConverter and register it with SimpleNitriteMapper. SimpleNitriteMapper will use this converter to map the Dart object to Nitrite document and vice-versa.","You can write your own implementation of EntityConverter or you can use the code generator to generate the implementation for you. More on this is discussed here.","Let's take an example of Product class.","To map to Nitrite document, we need to provide an implementation of EntityConverter for each class. Let's take a look at the converter for Product class.","Similarly, we need to provide converters for ProductId and Manufacturer classes.","Once the converters are ready, we need to register them with registerEntityConverter() method on NitriteBuilder instance.","we can also register the converters with SimpleNitriteMapper instance and then pass the instance to loadModule() method.","NitriteMapper is a NitritePlugin. So, you need to load it using loadModule() method on NitriteBuilder. More on Nitrite's module system can be found here.","If you have used the registerEntityConverter() method on NitriteBuilder instance, Nitrite will only use SimpleNitriteMapper to map the entities. It will ignore any other NitriteMapper implementation you have provided using loadModule() method."]},{"l":"Mapping Collections","p":["The EntityConverter interface provides some static methods to convert a collection of Dart objects to a collection of Nitrite documents and vice-versa.","These methods are:","fromList()- Converts a List of Dart objects to a List of Nitrite documents. If the type of the elements is a registered value type, it will return the same list without any conversion.","fromIterable()- Converts an Iterable of Dart objects to a List of Nitrite documents. If the type of the elements is a registered value type, it will return the same list without any conversion.","fromSet()- Converts a Set of Dart objects to a Set of Nitrite documents. If the type of the elements is a registered value type, it will return the same set without any conversion.","fromMap()- Converts a Map of key-value pair to a Map of Nitrite documents. If the type of the key or the value is a registered value type, it will not convert those objects to Nitrite document and return as is.","toList()- Converts a List of Nitrite documents to a List of Dart objects.","toIterable()- Converts an Iterable of Nitrite documents to an List of Dart objects.","toSet()- Converts a Set of Nitrite documents to a Set of Dart objects.","toMap()- Converts a Map of Nitrite documents to a Map of key value pair.","These methods are useful when you have a collection of objects as a property of a Dart class."]},{"l":"Example","p":["Let's take an example of Company class which has a map of Employee as a property.","To map this to Nitrite document, we need to provide an implementation of EntityConverter for Company class."]},{"l":"Code Generation","p":["Nitrite provides a code generator to generate the EntityConverter implementation for you. You have to annotate the class with some specific annotations and then run the code generator. The generated code will be saved in a separate file. You still need to register the generated converter with Nitrite.","The code generator is a separate package and more on the entity generator can be found here.","Nitrite uses below annotations to generate the EntityConverter implementation.","@Convertable","@DocumentKey","@IgnoredKey"]},{"i":"convertable","l":"@Convertable","p":["@Convertable annotation is used to mark a class as convertable. This annotation is mandatory for the code generator to work. This annotation specifies the code generator to generate the EntityConverter implementation for the class. It takes an optional parameter className which is used to specify the name of the converter class. If this parameter is not specified, then the code generator will use the class name with Converter suffix as the converter class name.","This will generate the following code:","You need to register the generated converters with Nitrite by calling registerEntityConverter() method on NitriteBuilder instance."]},{"i":"documentkey","l":"@DocumentKey","p":["@DocumentKey annotation is used to mark a field as a document key. This annotation provides an alias to the field. Normally the field name is used as the key in the Nitrite document. If you want to use a different name, then you can specify the alias using this annotation. This annotation can be used on a field or a getter/setter method.","This will generate the following code:"]},{"i":"ignoredkey","l":"@IgnoredKey","p":["@IgnoredKey annotation is used to mark a field as ignored. This annotation is useful when you want to ignore a field while mapping to Nitrite document. This annotation can be used on a field or a getter/setter method.","This will generate the following code:","The code generator imposes some limitations on the Dart classes. These limitations are discussed here."]},{"l":"Custom NitriteMapper","p":["Apart from SimpleNitriteMapper, you can also provide your own implementation of NitriteMapper. You need to implement NitriteMapper interface and provide your own implementation. Once the implementation is ready, you need to load it using loadModule() method on NitriteBuilder while building the database."]}],[{"l":"Write Operations"},{"l":"Inserting Entities","p":["Entities can be inserted into a repository using insert() or insertMay() method. It takes one or multiple Dart entities as input parameter respectively. It returns a future of WriteResult object.","If the entity has a NitriteId field, then the field value would be populated with a new NitriteId before inserting into the repository.","If any of the field is already indexed in the repository, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.insert event."]},{"l":"Inserting a Single Entity"},{"l":"Inserting Multiple Entities"},{"l":"Error Scenarios","p":["If a field of the entity is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["More information about WriteResult can be found here."]},{"l":"Updating Entities","p":["Entities can be updated using any of the following methods:","updateOne()- updates a single entity","update()- updates multiple entities using a filter and update entity","updateDocument()- updates multiple entities using a filter and update document","All update methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.update event."]},{"l":"Updating a Single Entity","p":["You can update a single entity using updateOne() method. It takes a Dart entity as input parameter. It returns a FutureWriteResult object. The entity must have a valid id field.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the idField getter must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Entity","p":["You can also upsert a single entity using updateOne() method. Along with the entity parameter, you need to pass a named parameter insertIfAbsent with value true. If the entity does not exist in the repository, then it will be inserted. Otherwise, it will be updated. The default value of insertIfAbsent is false."]},{"l":"Updating Using a Filter","p":["You can update multiple entities using a filter. It takes a Filter object as first input parameter. It takes a Dart entity as second input parameter. It returns a FutureWriteResult object.","If the filter result matches multiple entities, then all the entities will be updated."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a Dart entity as second input parameter. It takes a UpdateOptions object as third input parameter. It returns a FutureWriteResult object."]},{"l":"UpdateOptions","p":["More information about UpdateOptions can be found here."]},{"l":"Updating Using a Filter and Document","p":["You can update multiple entities using a filter. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It returns a FutureWriteResult object.","If the filter result matches multiple entities, then all the entities will be updated. The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"i":"updating-using-a-filter-document-and-options","l":"Updating Using a Filter, Document and Options","p":["You can update multiple entities using a filter, document and options. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It takes a boolean value as third input parameter. If the third input parameter is true, then it will only update the first entity matched by the filter. Otherwise, it will update all the entities matched by the filter. It returns a FutureWriteResult object.","The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"l":"Removing Entities","p":["Entities can be removed using any of the following methods:","removeOne()- removes a single entity","remove()- removes multiple entities using a filter","All remove methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.remove event."]},{"l":"Removing a Single Entity","p":["You can remove a single entity using removeOne() method. It takes a Dart entity as input parameter. It returns a FutureWriteResult object.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the idField getter must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple entities using a filter. It takes a Filter object as input parameter. It returns a FutureWriteResult object.","If the filter result matches multiple entities, then all the entities will be removed."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a boolean value as second input parameter. If the second input parameter is true, then it will remove only the first entity matched by the filter. Otherwise, it will remove all the entities matched by the filter. It returns a FutureWriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["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."]},{"l":"Filters","p":["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."]},{"l":"Find All Entities","p":["You can find all entities in a repository by calling find(). It returns a Cursor object."]},{"l":"Finding an Entity Using Id","p":["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."]},{"l":"Finding an Entity Using a Filter","p":["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."]},{"l":"Finding an Entity Using a Filter and Options","p":["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."]},{"l":"FindOptions","p":["More information about FindOptions can be found here."]},{"l":"Cursor","p":["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."]},{"l":"Iterating over Entities","p":["The Cursor extends Stream of entities. So, you can iterate over the entities using await for loop.","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."]},{"l":"Getting the Entities","p":["You can get the entities from a Cursor using toList() method. It returns a FutureListT object."]},{"l":"Getting the First Entity","p":["You can get the first entity from a Cursor using first getter. It returns a FutureT? object."]},{"l":"Getting the Size of the Cursor","p":["You can get the size of the cursor using length getter. It returns a Futureint object."]},{"l":"Projection","p":["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:","Then you can project the lastName and address.street fields. Then you define a new entity like this:","And then you can project the cursor like this:"]},{"l":"Join","p":["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:","And you want to join these two entities using userId field. Then you can define a new entity like this:","And then you can join the cursors like this:"]},{"l":"FindPlan","p":["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."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a repository. It supports indexing on a single field or multiple fields. It also supports full-text indexing.","Indexes for an entity can be defined using various annotations like @Id, @Index etc. More information about annotations can be found here. It can also be managed using various methods of ObjectRepository interface."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in an entity. It is useful when you want to search text content in an entity. It is also useful when you want to search text content in an entity in a language other than English.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. More information about custom index can be found here."]},{"l":"Creating an Index","p":["You can define indexes for an entity using annotations. You can also create indexes using ObjectRepository interface."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Using Annotations","p":["You can create a unique index on a single field or multiple fields using annotations. You can use @Id annotation to create a unique index on a single field. You can use @Index annotation to create a unique index on multiple fields."]},{"l":"Using ObjectRepository","p":["You can create a unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.nonUnique."]},{"i":"using-annotations-1","l":"Using Annotations","p":["You can create a non-unique index on a single field or multiple fields using annotations. You can use @Index annotation to create a non-unique index on multiple fields."]},{"i":"using-objectrepository-1","l":"Using ObjectRepository","p":["You can create a non-unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.nonUnique."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field or multiple fields by passing the index type as IndexType.fullText."]},{"i":"using-annotations-2","l":"Using Annotations","p":["You can create a full-text index on a single field using annotations. You can use @Index annotation to create a full-text index on a single field."]},{"i":"using-objectrepository-2","l":"Using ObjectRepository","p":["You can create a full-text index on a single field using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.fullText.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Iterable Field","p":["Nitrite supports creating index on iterable field. It will create index on each element of the iterable. For example, if you have an entity like this:","Then it will create index on each element of the tags list. You can also create index on tags field like this:"]},{"l":"Creating Index on Embedded Field","p":["Nitrite supports creating index on embedded field. For example, if you have entities like this:","Then it will create index on city field of Address entity. You can also create index on city field of Address entity like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes using listIndices() method. It returns a FutureCollection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a class which contains information about an index. It contains the following information:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the repository on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Repository","p":["You can get the size of a repository using size getter. It returns a future of the number of entities in the repository."]},{"l":"Clearing a Repository","p":["You can clear all the entities from a repository using clear() method. It removes all the entities from the repository and index entries from the indexes. It does not drop the repository."]},{"l":"Dropping a Repository","p":["You can drop a repository using drop() method. It removes all the entities from the repository and index entries from the indexes. It also drops all the indexes associated with the repository. It also removes the repository from the database.","You can call isDropped getter to check if the repository is dropped or not.","Any further operation on a dropped repository will throw NitriteIOException."]},{"l":"Closing a Repository","p":["You can close a repository using close() method. Any further operation on a closed repository will throw NitriteIOException.","After closing a repository, you must re-open it via Nitrite.getRepository() method to perform any operation on it.","You can call isOpen getter to check if the repository is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a repository to get notified on entity changes. The event listener is a function of type CollectionEventListener. It will receive CollectionEventInfo whenever an entity is inserted, updated or removed from the repository.","You can unsubscribe the event listener using unsubscribe() method."]},{"l":"CollectionEventInfo","p":["More on CollectionEventInfo can be found here."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a repository.","You can get/set attributes on a repository. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processor can be used to process the underlying documents of a repository. More on processors can be found here."]},{"l":"Registering a Processor","p":["You can register a processor on a repository using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a repository and decrypt a field after reading it from a repository.","More on this is described in Support."]}],[{"l":"Filters","p":["Filters are used to specify the criteria used to select documents from a collection or repository. It provides a way to specify conditions that the documents must meet to be included in the result set. Filters are used in conjunction with the find method. The find method returns all documents in a collection that match the specified filtering criteria.","Each filtering criteria is based on a field in the document. If the field is indexed, the find operation takes advantage of the index to speed up the operation. If the field is not indexed, the find operation scans the entire collection to find matching documents."]},{"l":"Fluent API","p":["Nitrite provides a fluent API to create filters via FluentFilter class. It provides a global method where to create a filter. The where method takes a field name as input parameter and returns a FluentFilter object. The FluentFilter object provides various methods to create a filter. Here is an example:","The above code will create a filter for the field name and then filter for equality. The find method will return all documents where the field name is equal to John.","For spatial filters, use the SpatialFluentFilter class for the fluent API. Similarly it also provides a global method where to create a filter. The where method takes a field name as input parameter and returns a SpatialFluentFilter object. The SpatialFluentFilter object provides various methods to create a filter. Here is an example:","More on spatial module can be found here."]},{"l":"Usage","p":["Filters are used with the find method of NitriteCollection or ObjectRepository to retrieve documents or entities that match the filter. Here's an example:","In this example, the where and eq methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"String Extensions","p":["Nitrite provides a String extension to create filters. It creates a filter for the field name specified in the string."]},{"l":"Operator Overloading","p":["Nitrite provides operator overloading to create filters. It creates a filter for the field name specified in the string.","There are various operators available for creating filters. Here is the list:",": Greater than filter","=: Greater than or equal to filter",": Less than filter","=: Less than or equal to filter","~: Not filter",": And filter","|: Or filter","These operators are also valid on the String extension of filter. More on this is discussed in the following sections."]},{"l":"Types of Filters","p":["Nitrite filters can be grouped into the following categories:","Comparison filters","Logical filters","Array filters","Evaluation filters","Spatial filters"]},{"l":"Comparison Filters","p":["Comparison filters are used to compare a field with a value. The following comparison filters are available:","Equality (eq): Matches all documents where the value of the field equals the specified value.","Inequality (notEq): Matches all documents where the value of the field is not equal to the specified value.","Greater than (gt): Matches all documents where the value of the field is greater than the specified value.","Greater than or equal to (gte): Matches all documents where the value of the field is greater than or equal to the specified value.","Less than (lt): Matches all documents where the value of the field is less than the specified value.","Less than or equal to (lte): Matches all documents where the value of the field is less than or equal to the specified value.","Within (within): Matches all documents where the value of the field equals any value in the specified array.","Not in (notIn): Matches all documents where the value of the field does not equal any value in the specified array.","Between (between): Matches all documents where the value of the field is between the specified values.","All (all): Matches all documents in the collection."]},{"l":"Equality Filter","p":["The equality filter is used to match documents where the value of a field equals the specified value. The following example shows how to use the equality filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Inequality Filter","p":["The inequality filter is used to match documents where the value of a field is not equal to the specified value. The following example shows how to use the inequality filter:","In this example, the where() and notEq() methods are used to create an inequality filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than Filter","p":["The greater than filter is used to match documents where the value of a field is greater than the specified value. The following example shows how to use the greater than filter:","In this example, the where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than or Equal To Filter","p":["The greater than or equal to filter is used to match documents where the value of a field is greater than or equal to the specified value. The following example shows how to use the greater than or equal to filter:","In this example, the where() and gte() methods are used to create a greater than or equal to filter that matches documents where the age field is greater than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than Filter","p":["The less than filter is used to match documents where the value of a field is less than the specified value. The following example shows how to use the less than filter:","In this example, the where() and lt() methods are used to create a less than filter that matches documents where the age field is less than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than or Equal To Filter","p":["The less than or equal to filter is used to match documents where the value of a field is less than or equal to the specified value. The following example shows how to use the less than or equal to filter:","In this example, the where() and lte() methods are used to create a less than or equal to filter that matches documents where the age field is less than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Within Filter","p":["The within filter is used to match documents where the value of a field equals any value in the specified array. The following example shows how to use the in filter:","In this example, the where() and within() methods are used to create an in filter that matches documents where the name field equals \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not In Filter","p":["The not in filter is used to match documents where the value of a field does not equal any value in the specified array. The following example shows how to use the not in filter:","In this example, the where() and notIn() methods are used to create a not in filter that matches documents where the name field does not equal \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Between Filter","p":["The between filter is used to match documents where the value of a field is between the specified values. The following example shows how to use the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. The filter is then passed to the find method to retrieve the matching documents.","There two other optional parameters available in the between method. The first parameter is lowerInclusive which is a boolean value to indicate whether the lower bound is inclusive or not. The default value is true. The second parameter is upperInclusive which is a boolean value to indicate whether the upper bound is inclusive or not. The default value is true."]},{"l":"All Filter","p":["The all filter is used to match all documents in the collection. The following example shows how to use the all filter:","In this example, the all constant is used to create an all filter that matches all documents in the collection. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Logical Filters","p":["Logical filters are used to combine multiple filters into a single filter. The following logical filters are supported:","And (and): Matches all documents that satisfy all the specified filters.","Or (or): Matches all documents that satisfy at least one of the specified filters.","Not (not): Matches all documents that do not satisfy the specified filter."]},{"l":"And Filter","p":["The and filter is used to match documents that satisfy all the specified filters. The following example shows how to use the and filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the and() method to create an and filter that matches documents where the name field equals \"John\" and the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The and() method can be used to combine any number of filters. The following example shows how to combine three filters:","Operators can also be used to combine filters. The following example shows how to combine three filters using operators:","The global and() method can also be used to combine filters. The following example shows how to combine three filters using the global and() method:","In this example, the and() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Or Filter","p":["The or filter is used to match documents that satisfy at least one of the specified filters. The following example shows how to use the or filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the or() method to create an or filter that matches documents where the name field equals \"John\" or the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The or() method can be used to combine any number of filters. The following example shows how to combine three filters:","Operators can also be used to combine filters. The following example shows how to combine three filters using operators:","The global or() method can also be used to combine filters. The following example shows how to combine three filters using the global or() method:","In this example, the or() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not Filter","p":["The not filter is used to match documents that do not satisfy the specified filter. The following example shows how to use the not filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The not() method is then used to create a not filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents.","The not() method can be used to negate any filter. The following example shows how to negate a greater than filter:"]},{"l":"Array Filters","p":["Array filters are used to match documents based on the values in an array field. The following array filters are supported:","Element match (elemMatch): Matches all documents where the array field contains at least one element that matches the specified filter."]},{"l":"Element Match Filter","p":["The element match filter is used to match documents where the array field contains at least one element that matches the specified filter. The following example shows how to use the element match filter:","Let's say we have a collection that contains documents with the following structure:","The following example shows how to use the element match filter to find all documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\":","In this example, the where() and elemMatch() methods are used to create an element match filter that matches documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\". The filter is then passed to the find method to retrieve the matching documents.","The elemMatch filter can be used to search an array of elements for a specific value. The following example shows how to use the elemMatch filter to find all documents where the data field contains at least one element that is greater than 2 or less than equal to 5:","The global $ variable is used to create a filter for the current element in the array. The $.gt(2).or($.lte(5)) filter is used to match documents where the data field contains at least one element that is greater than 2 or less than equal to 5. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Evaluation Filters","p":["Evaluation filters are used to match documents based on evaluating the value of any field in a document. The following evaluation filters are supported:","Text (text): Matches all documents which contain a specified full-text search expression.","Regex (regex): Matches all documents where values contain a specified regular expression."]},{"l":"Text Filter","p":["The text filter is used to match documents which contain a specified full-text search expression. The following example shows how to use the text filter:","In this example, the where() and text() methods are used to create a text filter that matches documents where the name field contains the word \"John\". The filter is then passed to the find method to retrieve the matching documents.","The text filter supports glob patterns. The following example shows how to use the text filter with glob patterns:","The text filter can only be used with a field that has a full-text index."]},{"l":"Regex Filter","p":["The regex filter is used to match documents where values contain a specified regular expression. The following example shows how to use the regex filter:","In this example, the where() and regex() methods are used to create a regex filter that matches documents where the name field matches the regular expression \"John.*\". The filter is then passed to the find method to retrieve the matching documents.","This filter scans the entire collection to find matching documents. It cannot take advantage of an index."]},{"l":"Spatial Filters","p":["Spatial filters are used to match documents based on the values in a spatial field. The following spatial filters are supported:","Near (near): Matches all documents where the spatial field is within the specified distance from the specified point.","Within (within): Matches all documents where the spatial field is within the specified shape.","Intersects (intersects): Matches all documents where the spatial field intersects the specified shape.","To use spatial filters, you need create a spatial index on the field, which needs the nitrite-spatial module to be loaded. More on this can be found here.","Spatial filters can only be used with a field that has a spatial index."]},{"l":"Near Filter","p":["The near filter is used to match documents where the value of the spatial field is near the specified point. The following example shows how to use the near filter:","In this example, the where() and near() methods are used to create a near filter that matches documents where the location field is within 1000 meters of the point (40.730610, -73.935242). The filter is then passed to the find method to retrieve the matching documents."]},{"i":"within-filter-1","l":"Within Filter","p":["The within filter is used to match documents where the value of the spatial field is within the specified shape. The following example shows how to use the within filter:","In this example, the where() and within() methods are used to create a within filter that matches documents where the location field is within the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Intersects Filter","p":["The intersects filter is used to match documents where the value of the spatial field intersects the specified shape. The following example shows how to use the intersects filter:","In this example, the where() and intersects() methods are used to create an intersects filter that matches documents where the location field intersects the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]}],[{"l":"Transaction","p":["A transaction is a single logical unit of work which accesses and possibly modifies the contents of a database. Transactions access data using read and write operations.","Nitrite supports transactional operations on its collections and repositories. A transaction can be committed or rolled back. Once a transaction is committed, all the changes are persisted to the disk. If a transaction is rolled back, all the changes are discarded."]},{"l":"Transaction on NitriteCollection","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a NitriteCollection, the Transaction.getCollection() method can be used. All the operations performed on the collection will be part of the transaction.","Nitrite also provides a Session.executeTransaction() method to execute a transactional operation. The Session.executeTransaction() method takes a callback function as an argument. The callback function will be executed inside a transaction.","If any exception occurs inside the transaction, the transaction will be rolled back. If you want to rollback a transaction only for certain exceptions, you can use the Session.executeTransaction() method with rollbackFor parameter. The rollbackFor parameter takes a list of exception types for which the transaction will be rolled back. For any other exceptions, the transaction will be committed.","Any find operations performed inside a transaction will return all the documents including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed documents."]},{"l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","NitriteCollection.createIndex()","NitriteCollection.rebuildIndex()","NitriteCollection.dropIndex()","NitriteCollection.dropAllIndices()","NitriteCollection.drop()","NitriteCollection.clear()","NitriteCollection.close()"]},{"l":"Transaction on ObjectRepository","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a ObjectRepository, the Transaction.getRepository() method can be used. All the operations performed on the repository will be part of the transaction.","Nitrite also provides a Session.executeTransaction() method to execute a transactional operation. The Session.executeTransaction() method takes a callback function as an argument. The callback function will be executed inside a transaction.","If any exception occurs inside the transaction, the transaction will be rolled back. If you want to rollback a transaction only for certain exceptions, you can use the Session.executeTransaction() method with rollbackFor parameter. The rollbackFor parameter takes a list of exception types for which the transaction will be rolled back. For any other exceptions, the transaction will be committed.","Any find operations performed inside a transaction will return all the entities including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed entities."]},{"i":"auto-commit-operations-1","l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","ObjectRepository.createIndex()","ObjectRepository.rebuildIndex()","ObjectRepository.dropIndex()","ObjectRepository.dropAllIndices()","ObjectRepository.drop()","ObjectRepository.clear()","ObjectRepository.close()"]},{"l":"Session","p":["A session represents a transactional context for a Nitrite database. Session is used to create a new transaction. A session should be closed after use to release any resources held by it. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Create a Session","p":["A session can be created using the Nitrite.createSession() method. Multiple sessions can be created for a Nitrite database."]},{"l":"Close a Session","p":["A session can be closed using the Session.close() method. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Checking If Session is Active","p":["A session can be checked if it is active or not using the Session.isActive getter."]},{"l":"Managing Transactions","p":["A transaction can be started using the Session.beginTransaction() method.","A transaction can be committed using the Transaction.commit() method. If a transaction is committed, all the changes are persisted to the disk.","A transaction can be rolled back using the Transaction.rollback() method. If a transaction is rolled back, all the changes are discarded.","A transaction can be closed using the Transaction.close() method. If a transaction is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Querying Transaction State","p":["The current state of a transaction can be retrieved using the Transaction.getState() method. It returns an enum of type TransactionState.","Possible values for TransactionState are:","TransactionState.active- The transaction is active.","TransactionState.committed- The transaction is committed.","TransactionState.partiallyCommitted- The transaction is partially committed.","TransactionState.closed- The transaction is closed.","TransactionState.failed- The transaction is failed.","TransactionState.aborted- The transaction is aborted."]}],[{"l":"Schema Migration","p":["A migration is a set of changes to the schema that can be applied to a database. Migrations are used to keep the database schema up to date with the codebase. It contains a queue of instructions that are executed in order to update the database schema from one version to the next.","The migration is executed only once for a specific schema version. If you want to execute the migration again, you need to change the schema version of the database.","For example, if you have a database with the schema version 1 and you want to update it to version 2, you need to apply the migration steps from version 1 and version 2.","The migration instructions are executed in the order they are added to the migration. The order of the instructions is important. For example, if you want to rename a field, you need to add the renameField instruction before the deleteField instruction. Otherwise, the deleteField instruction will fail.","Once a migration is applied to a database, it cannot be reverted. If you want to revert a migration, you need to create a new migration that will revert the changes.","Nitrite provides a set of instructions that can be used to update the database schema. These instructions can be grouped into three categories:","Database Instruction","Collection Instruction","Repository Instruction"]},{"l":"Database Instruction","p":["Database instructions are used to perform operations on the database. The following instructions are available:"]},{"l":"Add User","p":["Adds an instruction to set a user authentication to the database. The user will be used to open the database.","Nitrite database supports only one user authentication per database. If you try to add a new user when there is already a user authentication present, the migration will fail throwing a NitriteSecurityException."]},{"l":"Change Password","p":["Adds an instruction to change the password for the user authentication to the database.","The user authentication must be present in the database. If you try to change the password for a user that does not exist, the migration will fail throwing a NitriteSecurityException.","If you try to change the password for a user with a wrong password, the migration will also fail throwing a NitriteSecurityException."]},{"l":"Drop Collection","p":["Adds an instruction to drop a NitriteCollection from the database."]},{"l":"Drop Repository","p":["Adds an instruction to drop a ObjectRepository from the database. There are several ways to drop a repository:"]},{"l":"Drop by Type"},{"l":"Drop by Type and Key Name"},{"l":"Drop by EntityDecorator"},{"l":"Drop by EntityDecorator and Key Name"},{"l":"Drop by Entity Name"},{"l":"Drop by Entity Name and Key Name"},{"l":"Custom Instruction","p":["Adds a custom instruction to the migration. The custom instruction is a callback function that takes a Nitrite instance as an argument. The callback function can be used to perform any operation on the database."]},{"l":"Collection Instruction","p":["Collection instructions are used to perform operations on a NitriteCollection. The following instructions are available:"]},{"l":"Rename Collection","p":["Adds an instruction to rename a NitriteCollection."]},{"l":"Add Field","p":["Adds an instruction to add new field to the documents of a NitriteCollection."]},{"l":"Add Field with Null Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be null."]},{"l":"Add Field with Default Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be new-value."]},{"l":"Add Field with Generator","p":["The new field will be added to all the documents of the collection. The value of the new field will be the value returned by the Generator."]},{"l":"Generator","p":["A Generator is a function that takes a Document as input and returns a value. The value returned by the Generator will be used as the value of the new field."]},{"l":"Rename Field","p":["Adds an instruction to rename a field of the documents of a NitriteCollection."]},{"l":"Delete Field","p":["Adds an instruction to delete a field from the documents of a NitriteCollection."]},{"l":"Drop Index","p":["Adds an instruction to drop an index from a NitriteCollection.","The drop index instruction can be used to drop a single field index or a compound index."]},{"l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a NitriteCollection."]},{"l":"Create Index","p":["Adds an instruction to create an index on a NitriteCollection.","The create index instruction can be used to create a single field index or a compound index."]},{"l":"Repository Instruction","p":["Repository instructions are used to perform operations on a ObjectRepository. The following instructions are available:"]},{"l":"Rename Repository","p":["Adds an instruction to rename a ObjectRepository."]},{"i":"add-field-1","l":"Add Field","p":["Adds an instruction to add new field to the entity of a ObjectRepository."]},{"i":"add-field-with-null-value-1","l":"Add Field with Null Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be null."]},{"i":"add-field-with-default-value-1","l":"Add Field with Default Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be new-value."]},{"l":"Add Field with Generator Function","p":["The new field will be added to all the entities of the repository. The value of the new field will be the value returned by the Generator function.","More information about the Generator can be found here."]},{"i":"rename-field-1","l":"Rename Field","p":["Adds an instruction to rename a field of the entity of a ObjectRepository."]},{"i":"delete-field-1","l":"Delete Field","p":["Adds an instruction to delete a field from the entity of a ObjectRepository."]},{"l":"Change Data Type","p":["Adds an instruction to change the data type of a field of the entity of a ObjectRepository."]},{"l":"Type Converter","p":["A TypeConverter is a function that takes a value of one type as input and returns a value of another type. The value returned by the TypeConverter will be used as the value of the new field."]},{"l":"Change Id Field","p":["Adds an instruction to change the id field of the entity of a ObjectRepository."]},{"i":"drop-index-1","l":"Drop Index","p":["Adds an instruction to drop an index from a ObjectRepository.","The drop index instruction can be used to drop a single field index or a compound index."]},{"i":"drop-all-indexes-1","l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a ObjectRepository."]},{"i":"create-index-1","l":"Create Index","p":["Adds an instruction to create an index on a ObjectRepository.","The create index instruction can be used to create a single field index or a compound index."]}],[{"l":"Module System","p":["Nitrite is a modular database engine. The core functionality of Nitrite is provided by the nitrite module. The nitrite module is the only mandatory module for Nitrite. All other modules are optional and can be added to the project as per the requirement.","Nitrite's module system is built on top of NitritePlugin and NitriteModule interfaces. A module is a collection of plugins. While opening a database, all the modules must be loaded. Each module then load and initialize all the plugins it contains.","The nitrite module provides default implementation of all the interfaces. For example, the nitrite module provides in-memory storage implementation. If you want to use on-disk storage, you need to add a storage module to your project.","The main advantage of Nitrite's module system is that it allows you to extend the functionality of Nitrite without adding all the dependencies at once in your project. You only need to add dependencies that you want to use. This helps to keep the application size small.","You can write your own module and plugin and add it to the project. The module system also allows you to replace the default implementation of any plugin. For example, if you want to use a different storage engine, you can write your own storage module and add it to the project."]},{"l":"NitriteModule","p":["The NitriteModule interface is the base interface for all the modules. It encapsulates a set of plugins. A module must be loaded before opening a database.","To create a module, you need to implement the NitriteModule interface. The NitriteModule interface has a single getter plugins which returns a set of plugins."]},{"l":"Dynamic Module","p":["A dynamic module can be created using the global module() method. A dynamic module is a module which is not loaded from any package, instead it is created dynamically.","A dynamic module is useful when you want to create a module from a set of plugins at runtime."]},{"l":"Available Modules","p":["The following modules are available from Nitrite.","Storage Module","Spatial Module"]},{"l":"NitritePlugin","p":["The NitritePlugin interface is the base interface for all the plugins. A plugin is a single unit of functionality. A plugin must be loaded via a NitriteModule before opening a database."]},{"l":"Initializing Plugin","p":["A plugin can be initialized by implementing the initialize() method of the NitritePlugin interface. The initialize() method is called by the module when the plugin is loaded."]},{"l":"Closing Plugin","p":["A plugin can be closed by implementing the close() method of the NitritePlugin interface. The close() method is called by the module when the database is closed."]},{"l":"Available Plugins","p":["Following are the available plugins in Nitrite which can be used to extend the functionality of Nitrite:","NitriteStore- A plugin to provide storage functionality.","NitriteMapper- A plugin to provide object mapping functionality.","NitriteIndexer- A plugin to provide indexing functionality.","EntityConverter- A plugin to provide entity conversion functionality.","You can implement any of the above plugins to extend the functionality of Nitrite."]},{"l":"NitriteStore","p":["The NitriteStore interface is the base interface for all the storage plugins. A storage plugin is responsible for storing and retrieving data from the underlying storage. The NitriteStore interface extends the NitritePlugin interface.","A reference implementation of the NitriteStore interface can be found here."]},{"l":"NitriteMapper","p":["The NitriteMapper interface is the base interface for all the object mapping plugins. A mapper plugin is responsible for mapping an object to a document and vice-versa. The NitriteMapper interface extends the NitritePlugin interface."]},{"l":"NitriteIndexer","p":["The NitriteIndexer interface is the base interface for all the indexing plugins. An indexer plugin is responsible for indexing a document. The NitriteIndexer interface extends the NitritePlugin interface.","While creating a new index, Nitrite uses the indexType getter to determine the type of the index. The indexType getter must return a unique string for each type of index. So when you create a new index, you need to pass the same string to the IndexOptions.indexType."]},{"l":"EntityConverter","p":["An EntityConverter is a plugin which is responsible for converting an object to a document and vice-versa. The EntityConverter interface extends the NitritePlugin interface.","If Nitrite is using the default SimpleNitriteMapper, then all EntityConverter s from all the loaded modules are automatically registered with the mapper. If you are using a custom mapper, then you need to register the EntityConverter with the mapper manually.","One of the available EntityConverter in Nitrite is GeometryConverter from the spatial module. It is responsible for converting a Geometry object of JTS to a document and vice-versa. Once you load the spatial module, the GeometryConverter is automatically registered with the mapper. You can find more information about GeometryConverter here.","If you want to load multiple EntityConverter s, while opening the database, you can also create a dynamic module and load it instead of using the NitriteBuilder.registerEntityConverter() method multiple times."]}],[{"l":"Storage Module","p":["Nitrite provides a default storage module which is in-memory. It means all the data is stored in memory and is volatile. Once the application is closed, all the data is lost. If you want to persist the data, you want to use on-disk storage, you need to add a storage module to your project. There are choices of storage modules available for Nitrite. You can choose from below as per your requirement.","Hive Module","You can also write your own storage module and add it to the project. More details about writing your own storage module is available here."]}],[{"l":"Hive Modules","p":["Nitrite provides a persistent storage module based on Hive. Hive is a lightweight and blazing fast, file based key-value store written in pure Dart."]},{"l":"Adding Hive Module","p":["To use Hive module, you need add below dependency to your pubspec.yaml file:"]},{"l":"Using Hive Module","p":["To use Hive as your persistent storage, you need to load the HiveModule while opening the database. You can also configure the module as per your requirement.","Once the module is loaded, you can use the database as usual. All the data will be persisted in the file you specified."]},{"l":"Configuring Hive Module","p":["You can configure the Hive module as per your requirement. The following configuration options are available:","path- the file path where the database will be stored. It is a directory path.","backendPreference- the preference for the backend to use. It takes an enum HiveStorageBackendPreference.","encryptionCipher- the encryption cipher used to encrypt the database. If not specified, the database will not be encrypted. It takes a HiveCipher instance.","compactionStrategy- the compaction strategy to use. It takes a function of type CompactionStrategy.","crashRecovery- if set to true, the database will be recovered from crash. The default value is false.","addTypeAdapter()- you can add your own type adapter to the Hive database. It takes a TypeAdapter instance.","addStoreEventListener()- you can add your own store event listener to the Hive database. It takes a StoreEventListener function as argument.","Nitrite provides a builder pattern to configure the module. You can use the HiveModule.withConfig() method to get the builder instance. The builder has a build() method which returns the module instance.","For more details about Hive configuration, please visit Hive Documentation."]}],[{"l":"Custom Storage Modules","p":["The beauty of Nitrite is that it is highly extensible. You can write your own storage module and use it with Nitrite. Nitrite provides a simple interface StoreModule to write your own storage module."]},{"l":"StoreModule Interface","p":["To write a custom storage module, you need to implement the StoreModule interface. The interface has only one method getStore() which returns an implementation of NitriteStore interface.","Optionally, you can also implement the StoreConfig interface to provide configuration options for your storage module."]},{"l":"NitriteStore Interface","p":["The NitriteStore is the storage abstraction layer for Nitrite. It provides the basic operations required by Nitrite to store and retrieve data. A NitriteStore is responsible for managing NitriteMap and NitriteRTree instances which are the main building blocks of database collections."]},{"l":"StoreConfig Interface","p":["The StoreConfig interface provides configuration options for your storage module. You can use this interface to provide configuration options for your storage module."]},{"l":"NitriteMap Interface","p":["The NitriteMap interface is the abstraction layer for Nitrite's key-value store. It provides the basic operations required by a collection to store and retrieve data. A NitriteMap is responsible for managing NitriteId and Document instances which are the main unit of data storage in Nitrite."]},{"l":"NitriteRTree Interface","p":["The NitriteRTree interface is the abstraction layer for Nitrite's R-Tree. It provides the basic operations required by a spatial index to store and retrieve data."]},{"l":"Example","p":["Let's write a simple storage module which stores data in a Map object. The module will be a simple in-memory storage module. The module will be configured with a Map object and will use it to store data."]},{"l":"Store Module","p":["The following code snippet shows the implementation of the storage module."]},{"l":"Store Config","p":["The following code snippet shows the implementation of the store configuration.","And the builder class for the configuration."]},{"l":"Nitrite Store","p":["The following code snippet shows the implementation of the NitriteStore interface."]},{"l":"Nitrite Map","p":["The following code snippet shows the implementation of the NitriteMap interface."]},{"l":"Nitrite RTree","p":["The following code snippet shows the implementation of the NitriteRTree interface."]}],[{"l":"Spatial Module","p":["Nitrite Spatial module provides support for spatial queries. The module uses JTS port of the dart package dart_jts for spatial operations."]},{"l":"Adding Spatial Module","p":["To add Spatial module to your project, you need to add below dependency to your pubspec.yaml file:"]},{"l":"Using Spatial Module","p":["To use Spatial module, you need to load the SpatialModule while opening the database.","If you are using nitrite_hive_adapter as your storage module, you need to register the GeometryAdapter with the Hive database.","If Nitrite is using the default SimpleNitriteMapper, then the SpatialModule will automatically register the GeometryConverter with the mapper. If you are using your own custom mapper, then you need to register the GeometryConverter with the mapper."]},{"l":"GeometryConverter","p":["GeometryConverter is an EntityConverter which is used to convert Geometry object of Dart JTS to Document and vice-versa. It is used to store the Geometry object in the database."]},{"l":"Spatial Index","p":["Spatial module uses R-Tree index to store the spatial data.","To create a spatial index, you need to pass the index type as spatialIndex while creating the index. spatialIndex is a global constant defined in nitrite_spatial package.","Spatial index is not supported on multiple fields."]},{"l":"Spatial Filter","p":["Spatial module supports several filters to query spatial data. To know more about filters, please refer to Spatial Filters."]}],[{"l":"Usage","p":["Nitrite provides some additional functionalities via nitrite-support library. You can use the library to enable encryption, import/export database etc."]},{"l":"Adding nitrite-support","p":["To add nitrite-support to your project, add the following dependency to your pubspec.yaml file:"]}],[{"i":"importexport","l":"Import/Export","p":["Nitrite provides import/export functionality via nitrite-support library. You can import/export your database to/from a file in JSON format. You can choose to import/export the entire database or a specific collection."]},{"l":"Exporting Database","p":["To export the entire database in JSON format, you can use the Exporter class of nitrite-support library. You can use the Exporter.withOptions() method to construct an instance of Exporter.","The database must be in closed state before exporting."]},{"l":"Export Options","p":["collections- the list of collections to export. The rules for specifying the collection names are as follows:","dbFactory- the NitriteFactory function to use for export. It is used to create the Nitrite instance for export. It's a mandatory field.","exportData- whether to export data or not. It's an optional field, if not provided, it will be set to true.","exportIndices- whether to export indices or not. It's an optional field, if not provided, it will be set to true.","If a non-empty list is specified, only the collections in the list will be exported.","If a non-empty list is specified, only the repositories in the list will be exported.","If a non-empty map is specified, only the keyed repositories in the map will be exported.","If an empty list is specified, no collection will be exported.","If an empty list is specified, no repository will be exported.","If an empty map is specified, no keyed repository will be exported.","If null is specified, all collections will be exported.","If null is specified, all keyed repositories will be exported.","If null is specified, all repositories will be exported.","keyedRepositories- the map of keyed repositories to export. The rules for specifying the keyed repository names are as follows:","repositories- the list of repositories to export. The rules for specifying the repository names are as follows:","The Exporter.withOptions() method provides various options to configure the export process. You can set the following options:"]},{"l":"Example","p":["First create a method to create a Nitrite instance, which will be used as the nitriteFactory.","Then create the Exporter instance and export the database.","The source.json file will contain the exported data in JSON format."]},{"l":"Importing Database","p":["To import the entire database from an exported JSON data, you can use the Importer class of nitrite-support library. You can use the Importer.withOptions() method to construct an instance of Importer.","The database must be in closed state before importing."]},{"l":"Import Options","p":["The Importer.withOptions() method provides various options to configure the import process. You can set the following options:","dbFactory- the NitriteFactory function to use for import. It is used to create the Nitrite instance for import. It's a mandatory field."]},{"i":"example-1","l":"Example","p":["First create the Importer instance and configure it.","The nitrite_dest.db file will contain the imported data. You can open the database and use it."]}],[{"l":"Encryption","p":["Nitrite provides field level encryption support via nitrite-support module. You can encrypt your data using with or without a password."]},{"l":"Field Level Encryption","p":["Nitrite provides a StringFieldEncryptionProcessor utility class to encrypt and decrypt a field of a document. It is a Processor implementation. It uses AES to encrypt and decrypt data.","While initializing the StringFieldEncryptionProcessor, you can either provide a password or not. If you provide a password, the processor will use the password to encrypt and decrypt data. If you do not provide a password, the processor will use a random key to encrypt and decrypt data."]}],[{"l":"Java Examples","p":["Here we discuss about an Android todo application using Nitrite database. It uses nitrite as a file based storage engine. It demonstrates the use of Nitrite database in an Android application. The full source code is available here. This tutorial assumes that you have basic knowledge of Android development."]},{"l":"Setup","p":["To use Nitrite in your Android application, you need to add the following dependency in your app's build.gradle file.","Also add these pro-guard rules in your proguard-rules.pro file."]},{"l":"Entity Classes","p":["Define a simple Todo entity class to hold your todo data:","And, a list of TodoItem can be represented as:"]},{"l":"Database Initialization","p":["To initialize the database and to maintain a singleton instance of the database, you need to create a singleton class NitriteManager as follows:","Next create a data access layer DataBaseManager for CRUD operations:"]},{"l":"Activity","p":["Now you need to create two activities, one for the todo list and another for the menu."]},{"l":"Todo List Activity"},{"l":"Menu Activity","p":["The other resources are available in the source code."]}],[{"l":"Flutter Examples","p":["Here we discuss about a flutter todo application using Nitrite database. It uses nitrite as a file based storage engine. It also uses Riverpod for state management. It demonstrates the use of Nitrite database in a flutter application. The full source code is available here. This tutorial assumes that you have basic knowledge of flutter and riverpod."]},{"l":"Setup","p":["Add the following Nitrite dependencies in your pubspec.yaml file along with path_provider and riverpod_generator:"]},{"l":"Entity Classes","p":["Define a simple Todo entity class to hold your todo data:","And run the following command to generate the _$TodoEntityMixin:","This command will generate the models.no2.dart file in the same directory."]},{"l":"Database Initialization","p":["Next create a Nitrite database provider using riverpod:","Now using the dbProvider, create a todo ObjectRepository provider:","And other required providers for listing and searching:","Now again run the following command to generate the providers:"]},{"l":"UI","p":["Now define a todo widget to display a single time and define different actions on it:","And a todo list widget to display the list of todos:","Now you can use these widgets in your app and other widgets to add new todo, search, etc."]}],[{"l":"Showcase"},{"l":"Showcase Your Application","p":["If you are using Nitrite Database in your application, please fill up the form below. We will showcase your application in this page."]}],[{"l":"Frequently Asked Questions"},{"i":"what-is-nitrite","l":"What is Nitrite?","p":["Nitrite is a server-less embedded database ideal for desktop, mobile or small web applications. It's an open source, self-contained database. It supports both in-memory and file based persistent store."]},{"i":"is-nitrite-an-rdbms","l":"Is Nitrite an RDBMS?","p":["No, Nitrite is not an RDBMS. It's a NoSQL database. It's a document store with support for indexing, full-text search, event listeners, embedded and in-memory modes, encryption, and many other features."]},{"i":"what-is-the-difference-between-nitrite-and-sqlite","l":"What is the difference between Nitrite and SQLite?","p":["Nitrite is a NoSQL document store, whereas SQLite is an RDBMS. Nitrite is a document store, whereas SQLite is a relational store. Nitrite has pure Java, Dart implementations, whereas SQLite has C/C++ implementation and native bindings are needed for other languages."]},{"i":"which-platforms-are-supported-by-nitrite","l":"Which platforms are supported by Nitrite?","p":["Nitrite Java is supported on all platforms where Java is supported. Nitrite Flutter is supported on all platforms where Dart is supported."]},{"i":"when-should-i-use-nitrite","l":"When should I use Nitrite?","p":["Nitrite is a good choice for desktop, mobile or small web applications. It's a good choice for applications where you don't want to install a separate database server. It's a good choice for applications where you want to store data in-memory."]},{"i":"what-is-the-performance-of-nitrite","l":"What is the performance of Nitrite?","p":["Nitrite is highly performant, though it heavily depends on the underlying storage backend implementation. A JMH benchmark of Nitrite for Java is available here where you can find its performance amongst various storage backends against SQLite."]},{"i":"does-nitrite-support-replication-over-network","l":"Does Nitrite support replication over network?","p":["No, Nitrite doesn't support replication over network. It's a server-less embedded database. If you are looking for replication, you can subscribe to collection events using CollectionEventListener and replicate the data over network."]},{"i":"what-happened-to-nitrite-datagate-server","l":"What happened to Nitrite DataGate Server?","p":["Nitrite DataGate Server is now deprecated. It's no longer maintained due to lack of interest from the community. If you are looking for it to be revived, please vote here. If enough people are interested, it will be revived."]},{"i":"what-happened-to-nitrite-explorer","l":"What happened to Nitrite Explorer?","p":["Nitrite Explorer is now deprecated. It's no longer maintained due to lack of interest from the community. If you are looking for it to be revived, please vote here. If enough people are interested, it will be revived."]},{"i":"what-if-i-find-any-issues-in-the-documentation","l":"What if I find any issues in the documentation?","p":["If you find any issues in the documentation, please raise an issue here."]},{"i":"what-if-i-had-any-suggestionsquestions","l":"What if I had any suggestions/questions?","p":["If you have any suggestions or questions about Nitrite, please start a discussion here."]},{"i":"what-is-the-license-of-nitrite","l":"What is the license of Nitrite?","p":["Nitrite is licensed under Apache License 2.0. It's free to use in both commercial and non-commercial applications. If you are using Nitrite in your commercial application, please consider donating to the project."]},{"i":"how-can-i-donate-to-nitrite","l":"How can I donate to Nitrite?","p":["If you like Nitrite and want to support the project, please consider donating to the project. You can donate via GitHub Sponsors."]}]];
\ No newline at end of file
+window.__DOCS_SEARCH__ = [[{"i":"#","p":["Nitrite is a serverless, embedded, and self-contained NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Welcome to Nitrite Database","p":["NO sql O bject ( NO2 a.k.a Nitrite) is a serverless, embedded, and self-contained NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use. Currently, it is available in Java, Kotlin, and Flutter.","Nitrite database can be used in various scenarios where a lightweight, embedded, and serverless NoSQL database is required. Some of the use cases for Nitrite database are:","Mobile and desktop applications","IoT devices and sensors","Web applications and APIs","Prototyping and testing","Data caching and synchronization","Data analysis and reporting","Nitrite database is designed to be simple and easy to use, making it a good choice for small to medium-sized projects that require a fast and reliable data storage solution."]},{"i":"features","l":"✨ Features","p":["Embedded, serverless","Simple API","Document-oriented","Schemaless document collection and object repository","Extensible storage engines","Indexing and full-text search","Simple query api","In-memory and file-based store","Transaction support","Schema migration support","Encryption support"]},{"i":"what-nitrite-is-not","l":"⛔ What Nitrite is not","p":["Nitrite is not an RDBMS. It is also not a distributed NoSQL database like MongoDB or Cassandra. It does not have any server for external application to connect to."]},{"i":"getting-started","l":"\uD83D\uDE80 Getting Started","p":["Nitrite database is currently available in Java, Kotlin, and Flutter. Please visit respective language page for getting started guide.","Java","Kotlin","Flutter"]},{"i":"license","l":"\uD83D\uDCDD License","p":["Nitrite database is an open-source project released under the terms of the Apache License, Version 2.0."]},{"i":"support","l":"\uD83E\uDD1D Support","p":["Give a ⭐️ if this project helped you! Please consider donating to support the development and maintenance."]},{"i":"contributing","l":"\uD83D\uDC9A Contributing","p":["Contributions, issues and feature requests are welcome. Feel free to open a discussion thread here."]},{"i":"showcase","l":"\uD83C\uDF9E️ Showcase","p":["If you are using Nitrite database in your project, please let us know. We will be happy to showcase your project here."]}],[{"i":"#","p":["This guide will help you get started with Nitrite database. It will show you how to create a database, create a collection, insert documents, and query documents in Java."]},{"l":"Getting Started in Java","p":["To get started with Nitrite database, you need to add the Nitrite BOM to your project. The BOM will help you to manage the dependencies. Details of the BOM can be found here.","To add the BOM to your project, follow the steps below:"]},{"l":"Add dependency","p":["Add Nitrite dependency to your project:"]},{"l":"Maven","p":["Add the nitrite dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite dependency to your build.gradle file:","The latest released version of Nitrite can be found here."]},{"l":"Snapshot builds","p":["Snapshot builds are available from Sonatype.","To use snapshot builds, you need to add the following repository to your pom.xml file:","Or, if you are using Gradle, add the following repository to your build.gradle file:","You need Java 11 or above to use Nitrite database."]},{"i":"upgrade-from-3x","l":"Upgrade from 3.x","p":["If you are upgrading from 3.x, please note that there are lots of breaking changes in the API. The whole library is re-written from scratch. It is recommended to go through this guide before upgrading.","You need to use the MVStore as your storage module to upgrade from 3.x. The RocksDB module is not backward compatible.","Nitrite will try to migrate your existing database to the latest version on the provided you are using the MVStore module. If you are using the RocksDB module, you need to migrate your database manually. However, it is recommended to take a backup of your database before upgrading."]}],[{"l":"Nitrite Database","p":["Nitrite database is a serverless, embedded, and self-contained Java NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Creating a Database","p":["Nitrite database can be created in-memory or on-disk. By default, Nitrite database is created in-memory. To create a database on-disk, you need to add a storage module dependency to your project. More details about storage modules can be found here.","To create a database, you need to use NitriteBuilder class. To get an instance of NitriteBuilder, you need to call builder() method on Nitrite class."]},{"l":"In-memory Database","p":["If you don't load any on-disk storage module, then Nitrite will create an in-memory database. The below code snippet shows how to create a database in-memory."]},{"l":"On-disk Database","p":["The below code snippet shows how to create a database on-disk."]},{"l":"MVStore Backed Database","p":["More details about MVStore configuration can be found here."]},{"l":"RocksDB Backed Database","p":["More details about RocksDB configuration can be found here."]},{"l":"NitriteBuilder","p":["NitriteBuilder provides a fluent API to configure and create a Nitrite database instance."]},{"l":"Open or Create a Database","p":["To open or create a database, you need to call openOrCreate() method on NitriteBuilder instance. This method returns a Nitrite instance.","If no StoreModule is configured, then Nitrite will create an in-memory database. If a StoreModule is configured, then Nitrite will create a file-based database. If the database file does not exist, then Nitrite will create a new database file. If the database file already exists, then Nitrite will open the existing database file."]},{"l":"Securing a Database","p":["To secure a database, you need to call openOrCreate() method with username and password on NitriteBuilder instance. This method returns a Nitrite instance with the given username and password.","If you are using a file-based database, then you need to use the same username and password to open the database again. Otherwise, you will get a NitriteSecurityException.","Both username and password must be provided or both must be null."]},{"l":"Registering an EntityConverter","p":["Nitrite database uses a mapper to map Java entities to Nitrite documents and vice-versa. By default, Nitrite uses SimpleNitriteMapper as its mapper. This mapper uses EntityConverter s to map Java entities to Nitrite documents and vice-versa. To register an EntityConverter, you need to call registerEntityConverter() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More on EntityConverter can be found here."]},{"l":"Loading a Module","p":["Nitrite database is modular in nature. It provides various modules to extend its functionality. To load a module, you need to call loadModule() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance."]},{"l":"Loading a Storage Module"},{"l":"Loading a Jackson Based Mapper Module","p":["More on the Nitrite's module system can be found here."]},{"l":"Adding Migration Steps","p":["Nitrite database supports schema migration. To configure a migration step, you need to call addMigrations() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More on the schema migration can be found here."]},{"l":"Current Schema Version","p":["To configure the current schema version, you need to call schemaVersion() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","By default, the initial schema version is set to 1."]},{"l":"Field Separator Character","p":["To configure the field separator character, you need to call fieldSeparator() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","It is used to separate field names in a nested document. For example, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax.","The default field separator character is set to .."]}],[{"l":"Document","p":["Document is the basic unit of data in Nitrite database. It is a JSON like field-value pairs. The field is always a String and value can be anything including null. Document is schema-less, which means you can store any kind of data in a document.","Nitrite document supports nested document. That means, a value of a field can be another document. This allows you to create complex data structure."]},{"l":"Document Structure","p":["Nitrite document has the following structure."]},{"l":"Document Field","p":["Document field is always a String. It can be any valid string. The field cannot be null or empty string.","Below fields are reserved and cannot be used as key in a document.","_id: The unique identifier of a document. This field is auto-generated by Nitrite database during insertion.","_revision: The revision number of a document. This field is auto-generated by Nitrite database during insertion and update.","_source: The source collection name of a document.","_modified: The last modified timestamp of a document. This field is auto-generated by Nitrite database during insertion and update."]},{"l":"Document Value","p":["Document value can be any valid Java object. It can be null or any primitive type. It can also be a collection or an array. It can also be a nested document."]},{"l":"Document Identifier","p":["It is a unique identifier of a document. It is auto-generated by Nitrite database during insertion. It is a NitriteId and is stored as a String in the document."]},{"l":"NitriteId","p":["NitriteId is a unique identifier across the Nitrite database. Each document in a nitrite collection is associated with a NitriteId.","During insertion if a unique String value representing a 64-bit integer is supplied in the _id field of the document, then the value of the _id field will be used to generate the NitriteId. Otherwise, a new NitriteId will be generated and will be used in the _id field of the document.","The value of the NitriteId is a String representation of a 64-bit integer. The id generation is based on Twitter Snowflake algorithm. The id is composed of:","41 bits for time in milliseconds","10 bits for a machine id","12 bits for a sequence number","1 unused sign bit","The id is not guaranteed to be monotonically increasing. The id is sortable and the timestamp is stored in the id itself."]},{"l":"Retrieving a NitriteId from a Document","p":["The id can be retrieved from a document using Document.getId() method. If the document does not have an id, then it will create a new NitriteId and will set it in the document and will return the id. If the document already has an id, then it will return the id."]},{"l":"Field Separator","p":["To access a field of a nested document, or an element of an array field, you need to use the field separator.","Field separator is configurable. You can change the field separator character by calling NitriteBuilder.fieldSeparator() method.","Nitrite uses . as field separator by default."]},{"l":"Nested Document","p":["To specify or access a field of a nested document, you need to use the field separator character. That means, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax."]},{"l":"Array Field","p":["To specify or access an element of an array field, you need to use the index of the element. For example, if a document has a field phone which is an array, then the first element of the array can be accessed using phone.0 syntax."]},{"l":"Creating a Document","p":["To create a document, you need to use Document.createDocument() method."]},{"l":"Creating an Empty Document"},{"l":"Creating a Document with Initial Field-value Pair"},{"l":"Creating a Document with a Map"},{"l":"Updating a Document","p":["To update a document, you need to use Document.put() method. This method takes two parameters, the field name and the value. If the field already exists in the document, then the value will be updated. If the field does not exist, then it will be created."]},{"l":"Retrieving a Value from Document","p":["To retrieve a value from document, you need to use Document.get() method. This method takes one parameter, the field name. If the field exists in the document, then the value will be returned. If the field does not exist, then it will return null.","To retrieve a value from a nested document, use the field separator character.","To retrieve an element from an array field, use the index of the element."]},{"l":"Removing a Field from Document","p":["To remove a field from document, you need to use Document.remove() method. This method takes one parameter, the field name. If the field exists in the document, then it will be removed. If the field does not exist, then it will do nothing.","To remove a field from a nested document, use the field separator character.","To remove an element from an array field, use the index of the element."]},{"l":"Checking If a Field Exists in Document","p":["To check if a field exists in a document, you need to use Document.containsField() method. This method takes one parameter, the field name. If the field exists in the document, then it will return true. If the field does not exist, then it will return false.","To check if a field exists in a nested document, use the field separator character.","It cannot check if an element exists in an array field."]}],[{"l":"Introduction","p":["NitriteCollection represents a named document collection stored in a Nitrite database. It persists documents in a Nitrite database. It is similar to a table in relational database or a collection in MongoDB.","Each document in a collection is associated with a unique NitriteId. It exposes a set of methods to perform CRUD operations on documents. It also supports indexing and querying. It also supports event based notification on document changes.","NitriteCollection is thread-safe and supports concurrent read and write operations."]},{"l":"Creating a Collection","p":["A NitriteCollection can be created using Nitrite class. You need to call getCollection() method on Nitrite class to get an instance of a NitriteCollection.","If the collection does not exist, then it will be created automatically. If a collection with the same name already exists, then it will return the existing collection."]},{"l":"Limitations on Collection Name","p":["A collection name cannot be null or empty string. It cannot contains any of the following characters:","|(pipe)",":(colon)","+(plus)","The name also cannot be any of the following reserved words:","$nitrite_users","$nitrite_index_meta","$nitrite_index","$nitrite_meta_map","$nitrite_store_info","$nitrite_catalog"]}],[{"l":"Write Operations"},{"l":"Inserting Documents","p":["Documents can be inserted into a collection using insert() method. It takes one or multiple Document objects as input parameter. It returns a WriteResult object.","If the document has a NitriteId already in it's _id field, then it will be used as a unique key to identify the document in the collection. Otherwise, a new NitriteId will be generated and inserted into the document.","If any of the field is already indexed in the collection, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.Insert event."]},{"l":"Inserting a Single Document"},{"l":"Inserting Multiple Documents"},{"l":"Error Scenarios","p":["If the document is null, then it will throw a ValidationException.","If the document contains invalid value in it's _id field, then it will throw a InvalidIdException.","If there is another document with the same _id value in the collection, then it will throw a UniqueConstraintException.","If a field of the document is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["WriteResult contains the result of a write operation. It contains the following information:","Number of documents affected by the write operation. You can get this value using getAffectedCount() method.","List of NitriteId of the documents affected by the write operation. The WriteResults implements IterableNitriteId interface. So you can iterate over the WriteResult to get the NitriteId of the documents affected by the write operation."]},{"l":"Updating Documents","p":["Documents can be updated in a collection using update() method. There are several overloaded version of update() method. You can update a single document or multiple documents at a time. You can also update a document using a filter.","This operation will notify all the registered CollectionEventListener with EventType.Update event."]},{"l":"Updating a Single Document","p":["You can update a single document using update() method. It takes a Document object as input parameter. It returns a WriteResult object. The document must contain a valid NitriteId in it's _id field. The document must not be null.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Document","p":["You can upsert a single document using update() method. It takes a Document object as the first input parameter. It takes a boolean value as the second input parameter. If the second input parameter is true, then it will insert the document if it does not exist in the collection. Otherwise, it will update the document if it exists in the collection. It returns a WriteResult object. The document must not be null."]},{"l":"Updating Using a Filter","p":["You can update multiple documents using a filter. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It returns a WriteResult object. The document must not be null or empty.","If the filter result matches multiple documents, then all the documents will be updated."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It takes a UpdateOptions object as the third input parameter. It returns a WriteResult object. The document must not be null or empty."]},{"l":"UpdateOptions","p":["UpdateOptions is a class that contains several options for update operation. It has the following options:","insertIfAbsent: If this option is true, then it will insert the document if it does not exist in the collection. Otherwise, it will update the document if it exists in the collection.","justOnce: If this option is true, then it will update only the first document matched by the filter. Otherwise, it will update all the documents matched by the filter."]},{"l":"Removing Documents","p":["Documents can be removed from a collection using remove() method. There are several overloaded version of remove() method. You can remove a single document or multiple documents at a time using a filter.","This operation will notify all the registered CollectionEventListener with EventType.Remove event."]},{"l":"Removing a Single Document","p":["You can remove a single document using remove() method. It takes a Document object as input parameter. It returns a WriteResult object. The document must contain a valid NitriteId in it's _id field. The document must not be null.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple documents using a filter. It takes a Filter object as the input parameter. It returns a WriteResult object.","If the filter result matches multiple documents, then all the documents will be removed."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a boolean value as the second input parameter. If the second input parameter is true, then it will remove only the first document matched by the filter. Otherwise, it will remove all the documents matched by the filter. It returns a WriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["You can search documents in a collection using find() method. There are several overloaded version of find() method using a filter or find options or both. You can also search a document using it's NitriteId."]},{"l":"Filters","p":["Nitrite uses filters to find documents in a collection. A filter is a simple expression which evaluates to true or false. More information about filters can be found here."]},{"l":"Find All Documents","p":["You can find all documents in a collection by calling find(). It returns a DocumentCursor object."]},{"l":"Finding a Document Using NitriteId","p":["You can find a document using it's NitriteId by calling getById(). It takes a NitriteId as input parameter. It returns a Document object if the document is found. Otherwise, it returns null."]},{"l":"Finding a Document Using a Filter","p":["You can find a document using a filter. It takes a Filter object as input parameter. It returns a DocumentCursor object.","If there is an index on the field specified in the filter, this operation will use the index to find the document. Otherwise, it will scan the entire collection to find the document."]},{"l":"Finding a Document Using a Filter and Options","p":["You can find a document 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 DocumentCursor object."]},{"l":"FindOptions","p":["FindOptions is a class that contains several options for find operation. It has the following options:","limit: It specifies the maximum number of documents to be returned by the find operation.","skip: It specifies the number of documents to be skipped from the beginning of the result set.","orderBy: It specifies a collection of fields to be sorted by, along with sort order for each field. The sort order can be SortOrder.Ascending or SortOrder.Descending.","collator: It specifies a collator to be used for sorting. If this option is not specified, then the default collator will be used.","distinct: It specifies if the find operation should return distinct documents. If this option is true, then it will return only the distinct documents. Otherwise, it will return all the documents matched by the filter."]},{"l":"DocumentCursor","p":["DocumentCursor represents a result set of a find operation. It provides methods to iterate over the result of a find operation and retrieve the documents. It also provides methods like projection, join etc. to get the desired result."]},{"l":"Iterating over Documents","p":["The DocumentCursor extends Iterable interface. So, you can iterate over the documents using for-each loop.","A DocumentCursor is a lazy iterable. It does not load all the documents in memory at once. It loads the documents in memory as needed. So, it is memory efficient."]},{"l":"Getting the Documents","p":["You can get the documents at once using toList() and toSet() methods. It returns a List and Set of documents respectively."]},{"l":"Getting the First Document","p":["You can get the first document using firstOrNull() method. It returns the first document if the cursor has any document. Otherwise, it returns null."]},{"l":"Getting the Size of the Result Set","p":["You can get the size of the result set using size() method. It returns the number of documents in the result set."]},{"l":"Projection","p":["You can project the result set using project() method. It takes a Document as the only input parameter. It returns a RecordStreamDocument object.","The document must contain only the fields that needs to be projected. The field values must be null or a nested document. The condition holds true for nested documents as well.","Let's say you have a document like this:","And you want to project only lastName and address.street fields. Then you can do it like this:","The result set will contain only lastName and address.street fields."]},{"l":"Join","p":["You can join two cursors using join() method. It takes a DocumentCursor as the first input parameter. It takes a Lookup as the second input parameter. It returns a RecordStream object.","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 collections users and orders. The users collection contains the following documents:","And the orders collection contains the following documents:","Now, you want to join these two collections on userId field. Then you can do it like this:","The result set will contain the following documents:"]},{"l":"FindPlan","p":["FindPlan is a class that contains the execution plan of a find operation. It has the following properties:","byIdFilter: It contains the filter for finding a document using NitriteId.","indexScanFilter: It contains the filter for finding a document using index.","collectionScanFilter: It contains the filter for finding a document using full scan.","indexDescriptor: It contains the index descriptor for finding a document using index.","indexScanOrder: It contains the sort order for finding a document using index.","blockingSortOrder: It contains the sort order for finding a document using full scan.","skip: It contains the number of documents to be skipped from the beginning of the result set.","limit: It contains the maximum number of documents to be returned by the find operation.","distinct: It specifies if the find operation returns distinct documents.","collator: It specifies a collator to be used for sorting.","subPlans: It contains the sub plans for finding a document using or filter.","You can get the execution plan of a find operation using getFindPlan() method. It returns a FindPlan object."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a collection. It supports indexing on a single field or multiple fields. It also supports full-text indexing."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in a document. It is useful when you want to search text content in a document. It is also useful when you want to search text content in a document in a language other than English.","Document's _id field is always indexed.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. You need to implement NitriteIndexer interface to create your own custom index. NitriteIndexer is a NitritePlugin, so you need to register it using loadModule() method while opening a database. During index creation you need to pass the type of the custom index in IndexOptions object.","One of such custom index implementation can be found in spatial module. It provides spatial indexing on a collection. More on spatial indexing can be found here."]},{"l":"Creating an Index","p":["You can create an index on a collection using createIndex() method. There are several overloaded version of createIndex() method. You can create an index on a single field or multiple fields."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.NON_UNIQUE in IndexOptions object and the name of the fields on which the index will be created as input parameters."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field by passing the index type as IndexType.FULL_TEXT in IndexOptions object and the name of the field on which the index will be created as input parameters.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Array Field","p":["Nitrite supports creating index on array field. It will create index on each element of the array. For example, if you have a document like this:","You can create index on phones field like this:"]},{"l":"Creating Index on Nested Field","p":["You can create index on nested field. For example, if you have a document like this:","You can create a unique index on street field like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index on a collection using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index on a collection using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes on a collection using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes on a collection using listIndices() method. It returns a Collection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a simple class which contains the following information about an index:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists on a collection using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the collection on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Collection","p":["You can get the size of a collection using size() method. It returns the number of documents in the collection."]},{"l":"Clearing a Collection","p":["You can clear all the documents from a collection using clear() method. It removes all the documents from the collection and index entries from the indexes. It does not drop the collection."]},{"l":"Dropping a Collection","p":["You can drop a collection using drop() method. It removes all the documents from the collection and index entries from the indexes. It also drops all the indexes associated with the collection. It also removes the collection from the database.","You can call isDropped() method to check if the collection is dropped or not.","Any further operation on a dropped collection will throw NitriteIOException."]},{"l":"Closing a Collection","p":["You can close a collection using close() method. Any further operation on a closed collection will throw NitriteIOException.","After closing a collection, you must re-open it via Nitrite.getCollection() method to perform any operation on it.","You can call isOpen() method to check if the collection is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a collection to get notified on document changes. The event listener must implement CollectionEventListener interface. It will receive CollectionEventInfo whenever a document is inserted, updated or removed from the collection.","You can also remove an event listener from a collection."]},{"l":"CollectionEventInfo","p":["CollectionEventInfo contains the following information:","item- the document which is inserted, updated or removed.","originator- the name of the collection on which the event is fired.","eventType- the type of the event. It can be any of the following:","EventType.Insert","EventType.Update","EventType.Remove","EventType.IndexStart","EventType.IndexEnd","timestamp- the timestamp of the event."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a collection.","You can get/set attributes on a collection. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processors are used to process documents before writing them into or after reading them from a collection.","Processors are useful when you want to add some additional information in a document or transform any field before inserting or updating it in a collection. Processors are also useful when you want to validate a document before inserting or updating it in a collection.","Processors are registered on a collection. A collection can have multiple processors. Processors are executed in the order they are registered."]},{"l":"Registering a Processor","p":["You can register a processor on a collection using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a collection and decrypt a field after reading it from a collection.","More on this is described in Support."]}],[{"l":"Introduction","p":["ObjectRepository provides a simple and type-safe API for storing and retrieving Java objects in a Nitrite database. It is built on top of NitriteCollection and provides a similar API for CRUD operations. It also supports indexing and querying. It also supports event based notification on object changes.","ObjectRepository is thread-safe and supports concurrent read and write operations."]},{"l":"Creating a Repository","p":["An ObjectRepository can be created using Nitrite class. You need to call getRepository() method on Nitrite class to get an instance of an ObjectRepository. If the repository does not exist, then it will be created automatically. If a repository with the same name already exists, then it will return the existing repository.","There are several overloaded methods available to create a repository. You can pass a class type or an EntityDecorator along with an optional string key to create a repository."]},{"l":"Creating a Repository with Class Type","p":["You can create a ObjectRepository by passing a class type to getRepository() method."]},{"l":"Creating a Repository with Class Type and Key","p":["You can create a keyed ObjectRepository by passing a class type and a key to getRepository() method.","One typical use case of this keyed repository is to create a repository for each user in a multi-user application. The key can be the user name or user id. This will ensure that each user will have a separate repository for storing objects."]},{"l":"Creating a Repository with EntityDecorator","p":["A ObjectRepository can be created using EntityDecorator. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"Creating a Repository with EntityDecorator and Key","p":["A keyed ObjectRepository can be created using EntityDecorator and a key. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]}],[{"l":"Entity","p":["An entity is a Java object that can be stored in a Nitrite database. An entity can be a simple POJO or a complex object with nested objects. Every entity in an ObjectRepository is actually converted to a Document before storing in the underlying NitriteCollection. When an entity is converted to a Document, the fields of the entity are mapped to the fields of the Document. While retrieving an entity from the ObjectRepository, the Document is converted back to the entity.","Nitrite uses a NitriteMapper implementation to convert an entity to a Document and vice versa. By default, Nitrite uses an EntityConverter based implementation of NitriteMapper to convert an entity to a Document. You can also provide your own implementation of NitriteMapper to convert an entity to a Document.","More on NitriteMapper can be found here."]},{"l":"Annotations","p":["Nitrite uses annotations to define an entity. There are several annotations available to define an entity. These annotations are:","@Entity","@Id","@Index","@Indices","@InheritIndices","In case you cannot modify the entity class to add annotations, you can use EntityDecorator to add metadata to an entity. More on EntityDecorator can be found here."]},{"i":"entity","l":"@Entity","p":["@Entity annotation is used to mark a class as an entity. It is a class level annotation and takes optional value and indices parameters.","The value parameter is used to specify the name of the NitriteCollection in which the entity will be stored as a Document. If the value parameter is not specified, then the name of the collection will be the name of the class. The indices parameter is used to specify the indices on the repository."]},{"i":"id","l":"@Id","p":["@Id annotation is used to mark a field as the unique identifier of the entity. It is a field level annotation and takes optional fieldName parameter. The fieldName parameter is used to specify the name of the field in the document. If the fieldName parameter is not specified, then the name of the field in the class will be used as the name of the field in the document."]},{"l":"Embedded Id","p":["Nitrite also supports embedded id. The embedded id is used when the entity has a composite primary key. The @Id annotation can also be used to mark a field as an embedded id. In case of embedded id, the field should be marked with @Id annotation and the fieldName and embeddedFields parameters should be specified. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","The above @Id annotation will create a unique compound index on the fields - emp_Id.uniqueId and emp_Id.companyId."]},{"l":"Data Type","p":["The data type of the field marked with @Id annotation can be either Comparable or NitriteId. If the data type is Comparable, then the value of the field should be unique. If the data type is NitriteId, then the value of the field will be generated by Nitrite. But in the case of embedded id, the data type of the embedded fields can only be Comparable, it can't be NitriteId."]},{"i":"index","l":"@Index","p":["@Index annotation is used to declare an index on an entity field. It is a class level annotation and takes mandatory fields parameter and optional type parameter. The fields parameter is used to specify the names of the fields in the document to be indexed. The type parameter is used to specify the type of the index. If the type parameter is not specified, then the type of the index will be IndexType.UNIQUE."]},{"i":"indices","l":"@Indices","p":["@Indices annotation is used declare multiple indices on an entity. It is a class level annotation and takes mandatory value parameter. The value parameter is used to specify the list of @Index annotations."]},{"i":"inheritindices","l":"@InheritIndices","p":["@InheritIndices annotation is used to inherit the indices from the parent class. It is a class level annotation and takes no parameter.","If the @InheritIndices annotation is not specified, then the indices will not be inherited from the parent class."]},{"l":"EntityDecorator","p":["EntityDecorator is used to add metadata to an entity. If you cannot modify the entity class to add annotations, then you can use EntityDecorator to add metadata to an entity. You can use EntityDecorator to add id, indices and collection name for an entity.","While creating or opening a repository, you can pass an instance of EntityDecorator to the getRepository() method on Nitrite class. Nitrite will extract the metadata from the EntityDecorator instance and use it to create the repository.","To write an EntityDecorator for an entity, you need to implement the EntityDecorator interface. Let's take an example of a Product entity.","The Product entity has an embedded id ProductId and two indices on a nested object Manufacturer. To write an EntityDecorator for the Product entity, you need to implement the EntityDecorator interface as follows.","which is equivalent to the following entity class."]},{"l":"EntityId","p":["EntityId is used to specify the id field of an entity. It takes mandatory fieldName parameter and optional embeddedFields parameter in case of embedded id. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","Here productId is the name of the field in the document and uniqueId and productCode are the names of the fields in the embedded object. This will create a unique compound index on the fields - productId.uniqueId and productId.productCode."]},{"l":"EntityIndex","p":["EntityIndex is used to specify the indices on an entity. It takes mandatory type parameter and fields parameter. The type parameter is used to specify the type of the index. The fields parameter is used to specify the name of the fields in the document to be indexed.","Here manufacturer.name is the name of the field in the document and productName and manufacturer.uniqueId are the names of the fields in the document. This will create a non-unique index on the field manufacturer.name and a unique compound index on the fields - productName and manufacturer.uniqueId."]},{"l":"Entity Name","p":["Entity name is used to specify the name of the collection in which the entity will be stored. It takes no parameter.","Here product is the name of the NitriteCollection in which the product document will be stored."]}],[{"l":"NitriteMapper","p":["NitriteMapper is a simple and lightweight object mapper which can be used to map Java objects to Nitrite documents and vice-versa. Nitrite uses a NitriteMapper implementation to map Java entities to Nitrite documents and vice-versa while storing and retrieving objects from an ObjectRepository."]},{"l":"SimpleNitriteMapper","p":["Nitrite provides a default NitriteMapper implementation called SimpleNitriteMapper. This is a simple and lightweight mapper which uses EntityConverter to map a Java object to Nitrite documents and vice-versa. This mapper is suitable for most of the use cases."]},{"l":"EntityConverter","p":["EntityConverter is a simple interface which provides methods to convert a Java object to Nitrite document and vice-versa. For each class, you need to provide an implementation of EntityConverter and register it with SimpleNitriteMapper. SimpleNitriteMapper will use this converter to map the object to Nitrite document and vice-versa.","Let's take an example of Product class.","To map this to Nitrite document, we need to provide an implementation of EntityConverter for each class. Let's take a look at the converter for Product class.","Similarly, we need to provide converter for ProductId and Manufacturer class.","Once the converters are ready, we need to register them with registerEntityConverter() method on NitriteBuilder instance.","we can also register the converters with SimpleNitriteMapper instance and then pass the instance to loadModule() method.","NitriteMapper is a NitritePlugin. So, you need to load it using loadModule() method on NitriteBuilder. More on Nitrite's module system can be found here.","If you have used the registerEntityConverter() method on NitriteBuilder instance, Nitrite will only use SimpleNitriteMapper to map the entities. It will ignore any other NitriteMapper implementation you have provided using loadModule() method."]},{"l":"JacksonMapper","p":["Nitrite also provides a Jackson based mapper called JacksonMapper. This mapper uses Jackson's ObjectMapper to map Java entities to Nitrite documents and vice-versa. Here you don't need to provide any EntityConverter. Jackson will use its own ObjectMapper to map the entities.","More on this mapper can be found here."]},{"l":"Custom NitriteMapper","p":["Apart from SimpleNitriteMapper and JacksonMapper, you can also provide your own implementation of NitriteMapper. You need to implement NitriteMapper interface and provide your own implementation. Once the implementation is ready, you need to load it using loadModule() method on NitriteBuilder while building the database."]}],[{"l":"Write Operations"},{"l":"Inserting Entities","p":["Entities can be inserted into a repository using insert() method. It takes one or multiple Java entities as input parameter. It returns a WriteResult object.","If the entity has a NitriteId field, then the field value would be populated with a new NitriteId before inserting into the repository.","If any of the field is already indexed in the repository, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.Insert event."]},{"l":"Inserting a Single Entity"},{"l":"Inserting Multiple Entities"},{"l":"Error Scenarios","p":["If the entity is null, then it will throw a ValidationException.","If a field of the entity is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["More information about WriteResult can be found here."]},{"l":"Updating Entities","p":["Entities can be updated in a repository using update() method. There are several overloaded methods available for updating entities. All of them returns a WriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.Update event."]},{"l":"Updating a Single Entity","p":["You can update a single entity using update() method. It takes a Java entity as input parameter. It returns a WriteResult object.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the getIdField() method must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Entity","p":["You can upsert a single entity using update() method. It takes a Java entity as first input parameter. It takes a boolean value as second input parameter. If the second input parameter is true, then it will insert the entity if it does not exist in the repository. Otherwise, it will update the entity if it exists in the repository. It returns a WriteResult object."]},{"l":"Updating Using a Filter","p":["You can update multiple entities using a filter. It takes a Filter object as first input parameter. It takes a Java entity as second input parameter. It returns a WriteResult object. The entity must not be null.","If the filter result matches multiple entities, then all the entities will be updated."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a Java entity as second input parameter. It takes a UpdateOptions object as third input parameter. It returns a WriteResult object. The entity must not be null."]},{"l":"UpdateOptions","p":["More information about UpdateOptions can be found here."]},{"l":"Updating Using a Filter and Document","p":["You can update multiple entities using a filter and document. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It returns a WriteResult object. The document must not be null or empty.","If the filter result matches multiple entities, then all the entities will be updated. The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"i":"updating-using-a-filter-document-and-options","l":"Updating Using a Filter, Document and Options","p":["You can update multiple entities using a filter, document and options. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It takes a boolean value as third input parameter. If the third input parameter is true, then it will only update the first entity matched by the filter. Otherwise, it will update all the entities matched by the filter. It returns a WriteResult object. The document must not be null or empty.","The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"l":"Removing Entities","p":["Entities can be removed from a repository using remove() method. There are several overloaded methods available for removing entities. All of them returns a WriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.Remove event."]},{"l":"Removing a Single Entity","p":["You can remove a single entity using remove() method. It takes a Java entity as input parameter. It returns a WriteResult object.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the getIdField() method must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple entities using a filter. It takes a Filter object as input parameter. It returns a WriteResult object.","If the filter result matches multiple entities, then all the entities will be removed."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a boolean value as second input parameter. If the second input parameter is true, then it will remove only the first entity matched by the filter. Otherwise, it will remove all the entities matched by the filter. It returns a WriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["You can search entities in a repository using find() method. There are several overloaded version of find() method using a filter or find options or both. You can also search an entity using it's id."]},{"l":"Filters","p":["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."]},{"l":"Find All Entities","p":["You can find all entities in a repository by calling find(). It returns a Cursor object."]},{"l":"Finding an Entity Using Id","p":["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."]},{"l":"Finding an Entity Using a Filter","p":["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."]},{"l":"Finding an Entity Using a Filter and Options","p":["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."]},{"l":"FindOptions","p":["More information about FindOptions can be found here."]},{"l":"Cursor","p":["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."]},{"l":"Iterating over Entities","p":["The Cursor extends Iterable interface. So, you can iterate over the entities using for-each loop.","A Cursor is a lazy iterable. It will not load all the entities in memory at once. It will load the entities in memory as needed. So, it is memory efficient."]},{"l":"Getting the Entities","p":["You can get the entities from the cursor at once using toList() and toSet() method. It returns a List and Set of entities respectively."]},{"l":"Getting the First Entity","p":["You can get the first entity from the cursor using firstOrNull() method. It returns the first entity if the cursor is not empty. Otherwise, it returns null."]},{"l":"Getting the Size of the Cursor","p":["You can get the size of the cursor using size() method. It returns the number of entities in the cursor."]},{"l":"Projection","p":["You can project the cursor using project() method. It takes another entity type as input parameter. It returns a Cursor object of the projected entity.","The projected entity must contain only the fields that needs to be projected.","Let's say you have an entity like this:","And you want to project only lastName and address.street fields. Then you can define a new entity like this:","And then you can project the cursor like this:"]},{"l":"Join","p":["You can join two cursors using join() method. It takes another cursor as the first input parameter. It takes a Lookup as the second input parameter and type of the join as the third input parameter. It returns a RecordStream object.","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:","And you want to join these two entities using userId field. Then you can define a new entity like this:","And then you can join the cursors like this:"]},{"l":"FindPlan","p":["You can get the FindPlan of a cursor using getFindPlan() method. It returns a FindPlan object.","More information about FindPlan can be found here."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a repository. It supports indexing on a single field or multiple fields. It also supports full-text indexing.","Indexes for an entity can be defined using various annotations like @Id, @Index, @Indices etc. More information about annotations can be found here. It can also be managed using various methods of ObjectRepository interface."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in an entity. It is useful when you want to search text content in an entity. It is also useful when you want to search text content in an entity in a language other than English.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. More information about custom index can be found here."]},{"l":"Creating an Index","p":["You can define indexes for an entity using annotations. You can also create indexes using ObjectRepository interface."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Using Annotations","p":["You can create a unique index on a single field or multiple fields using annotations. You can use @Id annotation to create a unique index on a single field. You can use @Index annotation to create a unique index on multiple fields."]},{"l":"Using ObjectRepository","p":["You can create a unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.NON_UNIQUE."]},{"i":"using-annotations-1","l":"Using Annotations","p":["You can create a non-unique index on a single field or multiple fields using annotations. You can use @Index annotation to create a non-unique index on multiple fields."]},{"i":"using-objectrepository-1","l":"Using ObjectRepository","p":["You can create a non-unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.NON_UNIQUE."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field by passing the index type as IndexType.FULL_TEXT."]},{"i":"using-annotations-2","l":"Using Annotations","p":["You can create a full-text index on a single field using annotations. You can use @Index annotation to create a full-text index on a single field."]},{"i":"using-objectrepository-2","l":"Using ObjectRepository","p":["You can create a full-text index on a single field using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.FULL_TEXT.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Array Field","p":["Nitrite supports creating index on array field. It will create index on each element of the array. For example, if you have an entity like this:","You can create index on tags field like this:"]},{"l":"Creating Index on Embedded Field","p":["Nitrite supports creating index on embedded field. For example, if you have entities like this:","You can create index on name of Manufacturer entity via annotation like this:","Or you can create index on name of Manufacturer entity via ObjectRepository like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index on a repository using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index on a repository using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes on a repository using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes on a repository using listIndices() method. It returns a Collection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a simple class which contains the following information about an index:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists on a repository using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the repository on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Repository","p":["You can get the size of a repository using size() method. It returns the number of entities in the repository."]},{"l":"Clearing a Repository","p":["You can clear all the entities from a repository using clear() method. It removes all the entities from the repository and index entries from the indexes. It does not drop the repository."]},{"l":"Dropping a Repository","p":["You can drop a repository using drop() method. It removes all the entities from the repository and index entries from the indexes. It also drops all the indexes associated with the repository. It also removes the repository from the database.","You can call isDropped() method to check if the repository is dropped or not.","Any further operation on a dropped repository will throw NitriteIOException."]},{"l":"Closing a Repository","p":["You can close a repository using close() method. Any further operation on a closed repository will throw NitriteIOException.","After closing a repository, you must re-open it via Nitrite.getRepository() method to perform any operation on it.","You can call isOpen() method to check if the repository is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a repository to get notified on entity changes. The event listener must implement CollectionEventListener interface. It will receive CollectionEventInfo whenever an entity is inserted, updated or removed from the repository.","You can also remove an event listener from a collection."]},{"l":"CollectionEventInfo","p":["More on CollectionEventInfo can be found here."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a repository.","You can get/set attributes on a repository. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processor can be used to process the underlying documents of a repository. More on processors can be found here."]},{"l":"Registering a Processor","p":["You can register a processor on a repository using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a repository and decrypt a field after reading it from a repository.","More on this is described in Support."]}],[{"l":"Filters","p":["Filters are used to specify the criteria used to select documents from a collection or repository. It provides a way to specify conditions that the documents must meet to be included in the result set. Filters are used in conjunction with the find method. The find method returns all documents in a collection that match the specified filtering criteria.","Each filtering criteria is based on a field in the document. If the field is indexed, the find operation takes advantage of the index to speed up the operation. If the field is not indexed, the find operation scans the entire collection to find matching documents."]},{"l":"Fluent API","p":["Nitrite provides a fluent API to create filters via FluentFilter class. It provides a static where method that creates a new FluentFilter instance with the specified field name. Here's an example:","In this example, the FluentFilter.where method is used to create a filter that matches documents where the name field equals John. The filter is then passed to the find method to retrieve the matching documents.","For spatial filters, use the SpatialFluentFilter class for the fluent API. It provides a static where method that creates a new SpatialFluentFilter instance with the specified field name. Here's an example:","More on spatial module can be found here."]},{"l":"Usage","p":["Filters are used with the find method of NitriteCollection or ObjectRepository to retrieve documents or entities that match the filter. Here's an example:","In this example, the where and eq methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Types of Filters","p":["Nitrite filters can be grouped into the following categories:","Comparison filters","Logical filters","Array filters","Evaluation filters","Spatial filters"]},{"l":"Comparison Filters","p":["Comparison filters are used to compare a field with a value. The following comparison filters are supported:","Equality (eq): Matches all documents where the value of the field equals the specified value.","Inequality (notEq): Matches all documents where the value of the field is not equal to the specified value.","Greater than (gt): Matches all documents where the value of the field is greater than the specified value.","Greater than or equal to (gte): Matches all documents where the value of the field is greater than or equal to the specified value.","Less than (lt): Matches all documents where the value of the field is less than the specified value.","Less than or equal to (lte): Matches all documents where the value of the field is less than or equal to the specified value.","In (in): Matches all documents where the value of the field equals any value in the specified array.","Not in (notIn): Matches all documents where the value of the field does not equal any value in the specified array.","Between (between): Matches all documents where the value of the field is between the specified values.","All (all): Matches all documents in the collection."]},{"l":"Equality Filter","p":["The equality filter is used to match documents where the value of a field equals the specified value. The following example shows how to use the equality filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Inequality Filter","p":["The inequality filter is used to match documents where the value of a field is not equal to the specified value. The following example shows how to use the inequality filter:","In this example, the where() and notEq() methods are used to create an inequality filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than Filter","p":["The greater than filter is used to match documents where the value of a field is greater than the specified value. The following example shows how to use the greater than filter:","In this example, the where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than or Equal To Filter","p":["The greater than or equal to filter is used to match documents where the value of a field is greater than or equal to the specified value. The following example shows how to use the greater than or equal to filter:","In this example, the where() and gte() methods are used to create a greater than or equal to filter that matches documents where the age field is greater than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than Filter","p":["The less than filter is used to match documents where the value of a field is less than the specified value. The following example shows how to use the less than filter:","In this example, the where() and lt() methods are used to create a less than filter that matches documents where the age field is less than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than or Equal To Filter","p":["The less than or equal to filter is used to match documents where the value of a field is less than or equal to the specified value. The following example shows how to use the less than or equal to filter:","In this example, the where() and lte() methods are used to create a less than or equal to filter that matches documents where the age field is less than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"In Filter","p":["The in filter is used to match documents where the value of a field equals any value in the specified array. The following example shows how to use the in filter:","In this example, the where() and in() methods are used to create an in filter that matches documents where the name field equals \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not In Filter","p":["The not in filter is used to match documents where the value of a field does not equal any value in the specified array. The following example shows how to use the not in filter:","In this example, the where() and notIn() methods are used to create a not in filter that matches documents where the name field does not equal \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Between Filter","p":["The between filter is used to match documents where the value of a field is between the specified values. The following example shows how to use the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. The filter is then passed to the find method to retrieve the matching documents.","There are three overloaded versions of the between filter. The first version takes two parameters, the lower and upper bounds of the range. The second version takes an additional boolean parameter that indicates whether both the lower and upper bounds are inclusive or exclusive. The third version takes two additional boolean parameters that indicate whether the lower and upper bounds are inclusive or exclusive. The following example shows how to use the second version of the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. Both the lower and upper bounds are inclusive. The filter is then passed to the find method to retrieve the matching documents.","The following example shows how to use the third version of the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. The lower bound is inclusive and the upper bound is exclusive. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"All Filter","p":["The all filter is used to match all documents in the collection. The following example shows how to use the all filter:","In this example, the Filter.ALL constant is used to create an all filter that matches all documents in the collection. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Logical Filters","p":["Logical filters are used to combine multiple filters into a single filter. The following logical filters are supported:","And (and): Matches all documents that satisfy all the specified filters.","Or (or): Matches all documents that satisfy at least one of the specified filters.","Not (not): Matches all documents that do not satisfy the specified filter."]},{"l":"And Filter","p":["The and filter is used to match documents that satisfy all the specified filters. The following example shows how to use the and filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the and() method to create an and filter that matches documents where the name field equals \"John\" and the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The and() method can be used to combine any number of filters. The following example shows how to combine three filters:","The static Filter.and() method can also be used to combine multiple filters into a single filter. The following example shows how to combine two filters into a single filter:","In this example, the and() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Or Filter","p":["The or filter is used to match documents that satisfy at least one of the specified filters. The following example shows how to use the or filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the or() method to create an or filter that matches documents where the name field equals \"John\" or the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The or() method can be used to combine any number of filters. The following example shows how to combine three filters:","The static Filter.or() method can also be used to combine multiple filters into a single filter. The following example shows how to combine two filters into a single filter:","In this example, the or() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not Filter","p":["The not filter is used to match documents that do not satisfy the specified filter. The following example shows how to use the not filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The not() method is then used to create a not filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents.","The not() method can be used to negate any filter. The following example shows how to negate a greater than filter:"]},{"l":"Array Filters","p":["Array filters are used to match documents based on the values in an array field. The following array filters are supported:","Element match (elemMatch): Matches all documents where the array field contains at least one element that matches the specified filter."]},{"l":"Element Match Filter","p":["The element match filter is used to match documents where the array field contains at least one element that matches the specified filter. The following example shows how to use the element match filter:","Let's say we have a collection that contains documents with the following structure:","The following example shows how to use the element match filter to find all documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\":","In this example, the where() and elemMatch() methods are used to create an element match filter that matches documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\". The filter is then passed to the find method to retrieve the matching documents.","The elemMatch filter can be used to search an array of elements for a specific value. The following example shows how to use the elemMatch filter to find all documents where the data field contains at least one element that is greater than 2 or less than equal to 5:","The static FluentFilter.$ is used to create a filter for the current element in the array. The $.gt(2).or($.lte(5)) filter is used to match documents where the data field contains at least one element that is greater than 2 or less than equal to 5. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Evaluation Filters","p":["Evaluation filters are used to match documents based on evaluating the value of any field in a document. The following evaluation filters are supported:","Text (text): Matches all documents which contain a specified full-text search expression.","Regex (regex): Matches all documents where values contain a specified regular expression."]},{"l":"Text Filter","p":["The text filter is used to match documents which contain a specified full-text search expression. The following example shows how to use the text filter:","In this example, the where() and text() methods are used to create a text filter that matches documents where the name field contains the word \"John\". The filter is then passed to the find method to retrieve the matching documents.","The text filter supports glob patterns. The following example shows how to use the text filter with glob patterns:","The text filter can only be used with a field that has a full-text index."]},{"l":"Regex Filter","p":["The regex filter is used to match documents where values contain a specified regular expression. The following example shows how to use the regex filter:","In this example, the where() and regex() methods are used to create a regex filter that matches documents where the name field matches the regular expression \"John.*\". The filter is then passed to the find method to retrieve the matching documents.","This filter scans the entire collection to find matching documents. It cannot take advantage of an index."]},{"l":"Spatial Filters","p":["Spatial filters are used to match documents based on the values in a spatial field. The following spatial filters are supported:","Near (near): Matches all documents where the spatial field is within the specified distance from the specified point.","Within (within): Matches all documents where the spatial field is within the specified shape.","Intersects (intersects): Matches all documents where the spatial field intersects the specified shape.","To use spatial filters, you need create a spatial index on the field, which needs the nitrite-spatial module to be loaded. More on this can be found here.","Spatial filters can only be used with a field that has a spatial index."]},{"l":"Near Filter","p":["The near filter is used to match documents where the value of the spatial field is near the specified point. The following example shows how to use the near filter:","In this example, the where() and near() methods are used to create a near filter that matches documents where the location field is within 1000 meters of the point (40.730610, -73.935242). The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Within Filter","p":["The within filter is used to match documents where the value of the spatial field is within the specified shape. The following example shows how to use the within filter:","In this example, the where() and within() methods are used to create a within filter that matches documents where the location field is within the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Intersects Filter","p":["The intersects filter is used to match documents where the value of the spatial field intersects the specified shape. The following example shows how to use the intersects filter:","In this example, the where() and intersects() methods are used to create an intersects filter that matches documents where the location field intersects the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]}],[{"l":"Transaction","p":["A transaction is a single logical unit of work which accesses and possibly modifies the contents of a database. Transactions access data using read and write operations.","Nitrite supports transactional operations on its collections and repositories. A transaction can be committed or rolled back. Once a transaction is committed, all the changes are persisted to the disk. If a transaction is rolled back, all the changes are discarded."]},{"l":"Transaction on NitriteCollection","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a NitriteCollection, the Transaction.getCollection() method can be used. All the operations performed on the collection will be part of the transaction.","Transaction is a closeable resource. It is recommended to use it with try-with-resource block.","Any find operations performed inside a transaction will return all the documents including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed documents."]},{"l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","NitriteCollection.createIndex()","NitriteCollection.rebuildIndex()","NitriteCollection.dropIndex()","NitriteCollection.dropAllIndices()","NitriteCollection.drop()","NitriteCollection.clear()","NitriteCollection.close()"]},{"l":"Transaction on ObjectRepository","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a ObjectRepository, the Transaction.getRepository() method can be used. All the operations performed on the repository will be part of the transaction.","Transaction is a closeable resource. It is recommended to use it with try-with-resource block.","Any find operations performed inside a transaction will return all the entities including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed entities."]},{"i":"auto-commit-operations-1","l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","ObjectRepository.createIndex()","ObjectRepository.rebuildIndex()","ObjectRepository.dropIndex()","ObjectRepository.dropAllIndices()","ObjectRepository.drop()","ObjectRepository.clear()","ObjectRepository.close()"]},{"l":"Session","p":["A session represents a transactional context for a Nitrite database. Session is used to create a new transaction. A session should be closed after use to release any resources held by it. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Create a Session","p":["A session can be created using the Nitrite.createSession() method. Multiple sessions can be created for a Nitrite database."]},{"l":"Close a Session","p":["A session can be closed using the Session.close() method. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Checking Session State","p":["The current state of a session can be checked using the Session.checkState() method. If the session is not active, it will throw an TransactionException."]},{"l":"Managing Transactions","p":["A transaction can be started using the Session.beginTransaction() method.","A transaction can be committed using the Transaction.commit() method. If a transaction is committed, all the changes are persisted to the disk.","A transaction can be rolled back using the Transaction.rollback() method. If a transaction is rolled back, all the changes are discarded.","A transaction can be closed using the Transaction.close() method. If a transaction is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Querying Transaction State","p":["The current state of a transaction can be retrieved using the Transaction.getState() method. It returns an enum of type TransactionState.","The following states are available:","TransactionState.Active- The transaction is active.","TransactionState.Committed- The transaction is committed.","TransactionState.PartiallyCommitted- The transaction is partially committed.","TransactionState.Closed- The transaction is closed.","TransactionState.Failed- The transaction is failed.","TransactionState.Aborted- The transaction is aborted."]}],[{"l":"Schema Migration","p":["A migration is a set of changes to the schema that can be applied to a database. Migrations are used to keep the database schema up to date with the codebase. It contains a queue of instructions that are executed in order to update the database schema from one version to the next.","The migration is executed only once for a specific schema version. If you want to execute the migration again, you need to change the schema version of the database.","For example, if you have a database with the schema version 1 and you want to update it to version 2, you need to apply the migration steps from version 1 and version 2.","The migration instructions are executed in the order they are added to the migration. The order of the instructions is important. For example, if you want to rename a field, you need to add the renameField instruction before the deleteField instruction. Otherwise, the deleteField instruction will fail.","Once a migration is applied to a database, it cannot be reverted. If you want to revert a migration, you need to create a new migration that will revert the changes.","Nitrite provides a set of instructions that can be used to update the database schema. These instructions can be grouped into three categories:","Database Instruction","Collection Instruction","Repository Instruction"]},{"l":"Database Instruction","p":["Database instructions are used to perform operations on the database. The following instructions are available:"]},{"l":"Add User","p":["Adds an instruction to set a user authentication to the database. The user will be used to open the database.","Nitrite database supports only one user authentication per database. If you try to add a new user when there is already a user authentication present, the migration will fail throwing a NitriteSecurityException."]},{"l":"Change Password","p":["Adds an instruction to change the password for the user authentication to the database.","The user authentication must be present in the database. If you try to change the password for a user that does not exist, the migration will fail throwing a NitriteSecurityException.","If you try to change the password for a user with a wrong password, the migration will also fail throwing a NitriteSecurityException."]},{"l":"Drop Collection","p":["Adds an instruction to drop a NitriteCollection from the database."]},{"l":"Drop Repository","p":["Adds an instruction to drop a ObjectRepository from the database. There are several ways to drop a repository:"]},{"l":"Drop by Class"},{"l":"Drop by Class and Key Name"},{"l":"Drop by EntityDecorator"},{"l":"Drop by EntityDecorator and Key Name"},{"l":"Drop by Repository Type Name"},{"l":"Drop by Repository Type Name and Key Name"},{"l":"Custom Instruction","p":["Adds a custom instruction to perform a user defined operation on the database. The custom instruction is a callback that takes a Nitrite instance as an argument. The callback can be used to perform any operation on the database."]},{"l":"Collection Instruction","p":["Collection instructions are used to perform operations on a NitriteCollection. The following instructions are available:"]},{"l":"Rename Collection","p":["Adds an instruction to rename a NitriteCollection."]},{"l":"Add Field","p":["Adds an instruction to add new field to the documents of a NitriteCollection."]},{"l":"Add Field with Null Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be null."]},{"l":"Add Field with Default Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be new-value."]},{"l":"Add Field with Generator","p":["The new field will be added to all the documents of the collection. The value of the new field will be the value returned by the Generator."]},{"l":"Generator","p":["A Generator is a functional interface that takes a Document as input and returns a value. The value returned by the Generator will be used as the value of the new field."]},{"l":"Rename Field","p":["Adds an instruction to rename a field of the documents of a NitriteCollection."]},{"l":"Delete Field","p":["Adds an instruction to delete a field from the documents of a NitriteCollection."]},{"l":"Drop Index","p":["Adds an instruction to drop an index from a NitriteCollection.","The drop index instruction can be used to drop a single field index or a compound index."]},{"l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a NitriteCollection."]},{"l":"Create Index","p":["Adds an instruction to create an index on a NitriteCollection.","The create index instruction can be used to create a single field index or a compound index."]},{"l":"Repository Instruction","p":["Repository instructions are used to perform operations on a ObjectRepository. The following instructions are available:"]},{"l":"Rename Repository","p":["Adds an instruction to rename a ObjectRepository."]},{"i":"add-field-1","l":"Add Field","p":["Adds an instruction to add new field to the entity of a ObjectRepository."]},{"i":"add-field-with-null-value-1","l":"Add Field with Null Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be null."]},{"i":"add-field-with-default-value-1","l":"Add Field with Default Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be 0."]},{"l":"Add Field with Generator Function","p":["The new field will be added to all the entities of the repository. The value of the new field will be the value returned by the Generator function.","More information about the Generator can be found here."]},{"i":"rename-field-1","l":"Rename Field","p":["Adds an instruction to rename a field of the entity of a ObjectRepository."]},{"i":"delete-field-1","l":"Delete Field","p":["Adds an instruction to delete a field from the entity of a ObjectRepository."]},{"l":"Change Data Type","p":["Adds an instruction to change the data type of a field of the entity of a ObjectRepository."]},{"l":"Type Converter","p":["A TypeConverter is a functional interface that takes a value of one type as input and returns a value of another type. The value returned by the TypeConverter will be used as the value of the new field."]},{"l":"Change Id Field","p":["Adds an instruction to change the id field of the entity of a ObjectRepository."]},{"i":"drop-index-1","l":"Drop Index","p":["Adds an instruction to drop an index from a ObjectRepository.","The drop index instruction can be used to drop a single field index or a compound index."]},{"i":"drop-all-indexes-1","l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a ObjectRepository."]},{"i":"create-index-1","l":"Create Index","p":["Adds an instruction to create an index on a ObjectRepository.","The create index instruction can be used to create a single field index or a compound index."]}],[{"l":"Module System","p":["Nitrite is a modular database engine. The core functionality of Nitrite is provided by the nitrite module. The nitrite module is the only mandatory module for Nitrite. All other modules are optional and can be added to the project as per the requirement.","Nitrite's module system is built on top of NitritePlugin and NitriteModule interfaces. A module is a collection of plugins. While opening a database, all the modules must be loaded. Each module then load and initialize all the plugins it contains.","The nitrite module provides default implementation of all the interfaces. For example, the nitrite module provides in-memory storage implementation. If you want to use on-disk storage, you need to add a storage module to your project.","The main advantage of Nitrite's module system is that it allows you to extend the functionality of Nitrite without adding all the dependencies at once in your project. You only need to add dependencies that you want to use. This helps to keep the application size small.","You can write your own module and plugin and add it to the project. The module system also allows you to replace the default implementation of any plugin. For example, if you want to use a different storage engine, you can write your own storage module and add it to the project."]},{"l":"NitriteModule","p":["The NitriteModule interface is the base interface for all the modules. It encapsulates a set of plugins. A module must be loaded before opening a database.","To create a module, you need to implement the NitriteModule interface. The NitriteModule interface has a single method plugins() which returns a set of plugins."]},{"l":"Dynamic Module","p":["A dynamic module can be created using the static module() method of the NitriteModule interface. A dynamic module is a module which is not loaded from a jar file. It is created at runtime.","A dynamic module is useful when you want to create a module from a set of plugins at runtime."]},{"l":"Available Modules","p":["The following modules are available from Nitrite.","Storage Module","Jackson Module","Spatial Module"]},{"l":"NitritePlugin","p":["The NitritePlugin interface is the base interface for all the plugins. A plugin is a single unit of functionality. A plugin must be loaded via a NitriteModule before opening a database."]},{"l":"Initializing Plugin","p":["A plugin can be initialized by implementing the initialize() method of the NitritePlugin interface. The initialize() method is called by the module when the plugin is loaded."]},{"l":"Closing Plugin","p":["A NitritePlugin is a closable resource. The close method is called by the Nitrite when the plugin is unloaded to release any resources held by the plugin."]},{"l":"Available Plugins","p":["Following are the available plugins in Nitrite which can be used to extend the functionality of Nitrite:","NitriteStore- A plugin to provide storage functionality.","NitriteMapper- A plugin to provide object mapping functionality.","NitriteIndexer- A plugin to provide indexing functionality.","EntityConverter- A plugin to provide entity conversion functionality.","You can implement any of the above plugins to extend the functionality of Nitrite."]},{"l":"NitriteStore","p":["The NitriteStore interface is the base interface for all the storage plugins. A storage plugin is responsible for storing and retrieving data from the underlying storage. The NitriteStore interface extends the NitritePlugin interface.","A reference implementation of the NitriteStore interface can be found here."]},{"l":"NitriteMapper","p":["The NitriteMapper interface is the base interface for all the object mapping plugins. A mapper plugin is responsible for mapping an object to a document and vice-versa. The NitriteMapper interface extends the NitritePlugin interface.","JacksonMapper is one of the available mapper plugins in Nitrite. It uses Jackson to map an object to a document and vice-versa. You can find more information about JacksonMapper here."]},{"l":"NitriteIndexer","p":["The NitriteIndexer interface is the base interface for all the indexing plugins. An indexer plugin is responsible for indexing a document. The NitriteIndexer interface extends the NitritePlugin interface.","While creating a new index, Nitrite uses the getIndexType() method of the NitriteIndexer interface to determine the type of the index. The getIndexType() method returns a string which represents the type of the index. So when you create a new index, you need to pass the same string to the IndexOptions.indexType."]},{"l":"EntityConverter","p":["An EntityConverter is a plugin which is responsible for converting an object to a document and vice-versa. The EntityConverter interface extends the NitritePlugin interface.","If Nitrite is using the default SimpleNitriteMapper, then all EntityConverter s from all the loaded modules are automatically registered with the mapper. If you are using a custom mapper, then you need to register the EntityConverter with the mapper manually.","One of the available EntityConverter in Nitrite is GeometryConverter from the spatial module. It is responsible for converting a Geometry object of JTS to a document and vice-versa. Once you load the spatial module, the GeometryConverter is automatically registered with the mapper. You can find more information about GeometryConverter here.","If you want to load multiple EntityConverter s, while opening the database, you can also create a dynamic module and load it instead of using the NitriteBuilder.registerEntityConverter() method multiple times."]},{"l":"Nitrite Bill of Materials","p":["The nitrite-bom is a bill of materials (BOM) for Nitrite. It is a pom file that contains the version of all the modules. It is useful when you want to use multiple modules in your project and want to keep the version of all the modules in sync."]},{"l":"Maven","p":["Add the nitrite dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite dependency to your build.gradle file:"]}],[{"l":"Storage Module","p":["Nitrite provides a default storage module which is in-memory. It means all the data is stored in memory and is volatile. Once the application is closed, all the data is lost. If you want to persist the data, you want to use on-disk storage, you need to add a storage module to your project. There are choices of storage modules available for Nitrite. You can choose any one of them as per your requirement.","MVStore Module","RocksDB Module","You can also write your own storage module and add it to the project. More details about writing your own storage module is available here."]}],[{"l":"MVStore Modules","p":["Nitrite provides a persistent storage module based on MVStore. MVStore is a pure Java key-value store database. It is a single file based database. It is very fast and lightweight."]},{"l":"Adding MVStore Module","p":["Add MVStore module to your project:"]},{"l":"Maven","p":["Add the MVStore dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the MVStore dependency to your build.gradle file:"]},{"l":"Using MVStore Module","p":["To use MVStore as your persistent storage, you need to load the MVStoreModule while opening the database. You can also configure the module as per your requirement.","Once the module is loaded, you can use the database as usual. All the data will be persisted in the file you specified."]},{"l":"Configuring MVStore Module","p":["You can configure the MVStore module as per your requirement. The following configuration options are available:","filePath- the file path where the database will be stored.","autoCommitBufferSize- the size of the buffer used for auto-commit. When the buffer is full, the changes are automatically committed to the database. The default buffer size is 1024.","encryptionKey- the encryption key used to encrypt the database. If not specified, the database will not be encrypted.","readOnly- if set to true, the database will be opened in read-only mode. The default value is false.","compress- if set to true, the database will be compressed. The default value is false.","compressHigh- if set to true, the database will be compressed using high compression. The default value is false. It may result in slower read and write performance but smaller file size on disk.","autoCommit- if set to true, all changes will be committed immediately. If set to false, changes will be buffered until the buffer is full or Nitrite.commit() is called. The default value is true.","recoveryMode- if set to true, the database will be opened in recovery mode. The default value is false.","cacheSize- the cache size in MB. The default value is 16 MB.","cacheConcurrency- the read cache concurrency used by MVStore. Default is 16 segments.","pageSplitSize- the amount of memory a MVStore page should contain at most, in bytes, before it is split. The default is 16 KB.","fileStore- the file store used by MVStore.","Nitrite provides a builder pattern to configure the module. You can use the MVStoreModule.withConfig() method to get the builder instance. The builder has a build() method which returns the configured module."]},{"i":"upgrading-from-3x","l":"Upgrading from 3.x","p":["If you are upgrading from Nitrite 3.x, you need to use the MVStore module as your storage module if you want to automatically upgrade your database. Any other storage module will not be able to upgrade your database automatically; you need to write your own upgrade logic.","Nitrite 3.x uses MVStore version 1.4.x. Nitrite 4.x uses MVStore version 2.2.x. The MVStore version 2.2.x is not backward compatible with version 1.4.x. So, Nitrite 4.x will try to upgrade your database automatically when you open it for the first time on a . If the upgrade fails, you need to write your own upgrade logic. However, it is recommended to take a backup of your database before upgrading."]}],[{"l":"RocksDB Module","p":["Nitrite provides a persistent storage module based on RocksDB. RocksDB is a persistent key-value store for fast storage. It is based on a log-structured merge-tree (LSM tree) data structure. It is very fast and lightweight. Nitrite uses the JNI wrapper of RocksDB.","RocksDB's column family feature is used to store the data of each collection."]},{"l":"Adding RocksDB Module","p":["Add RocksDB module to your project:"]},{"l":"Maven","p":["Add the RocksDB dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the RocksDB dependency to your build.gradle file:"]},{"l":"Using RocksDB Module","p":["To use RocksDB as your persistent storage, you need to load the RocksDBModule while opening the database. You can also configure the module as per your requirement.","Once the module is loaded, you can use the database as usual. All the data will be persisted in the file you specified."]},{"l":"Configuring RocksDB Module","p":["You can configure the RocksDB module as per your requirement. The following configuration options are available:","filePath- the file path where the database will be stored.","options- the RocksDB's Options object. You can configure RocksDB as per your requirement. The default value is null.","dbOptions- the RocksDB's DBOptions object. You can configure RocksDB as per your requirement. The default value is null.","columnFamilyOptions- the RocksDB's ColumnFamilyOptions object. You can configure RocksDB as per your requirement. The default value is null.","objectFormatter- the ObjectFormatter to be used to serialize/deserialize objects. The default implementation is KryoObjectFormatter which is based on Kryo serializer."]},{"l":"Object Serialization","p":["RocksDB is a key-value store database. It stores data in byte array format. To store objects in RocksDB, Nitrite uses a serializer. Nitrite uses ObjectFormatter to serialize/deserialize objects. The default implementation is KryoObjectFormatter which is based on Kryo serializer. You can also provide your own implementation of ObjectFormatter to serialize/deserialize objects."]},{"l":"Implementing ObjectFormatter","p":["To implement your own ObjectFormatter, you need to implement the ObjectFormatter interface.","Once you have implemented the ObjectFormatter, you can use it while configuring the RocksDB module.","Normally, you don't need to implement your own ObjectFormatter. The default implementation is good enough for most of the use cases."]},{"l":"Limitations","p":["RocksDB JNI does not support RTree, so RocksDB storage adapter does not provide any RTree backed NitriteRTree implementation. Though there is a workaround implementation of NitriteRTree using RocksDB, it is not recommended to use it in production. It is only for testing purpose. Hence, RocksDB storage adapter is not recommended for spatial data indexing.","If you want to use spatial data indexing, you can use Spatial Module with MVStore storage adapter. MVStore storage adapter provides RTree backed NitriteRTree implementation."]}],[{"l":"Custom Storage Modules","p":["The beauty of Nitrite is that it is highly extensible. You can write your own storage module and use it with Nitrite. Nitrite provides a simple interface StoreModule to write your own storage module."]},{"l":"StoreModule Interface","p":["To write a custom storage module, you need to implement the StoreModule interface. The interface has only one method getStore() which returns an implementation of NitriteStore interface.","Optionally, you can also implement the StoreConfig interface to provide configuration options for your storage module."]},{"l":"NitriteStore Interface","p":["The NitriteStore is the storage abstraction layer for Nitrite. It provides the basic operations required by Nitrite to store and retrieve data. A NitriteStore is responsible for managing NitriteMap and NitriteRTree instances which are the main building blocks of database collections."]},{"l":"StoreConfig Interface","p":["The StoreConfig interface provides configuration options for your storage module. You can use this interface to provide configuration options for your storage module."]},{"l":"NitriteMap Interface","p":["The NitriteMap interface is the abstraction layer for Nitrite's key-value store. It provides the basic operations required by a collection to store and retrieve data. A NitriteMap is responsible for managing NitriteId and Document instances which are the main unit of data storage in Nitrite."]},{"l":"NitriteRTree Interface","p":["The NitriteRTree interface is the abstraction layer for Nitrite's R-Tree. It provides the basic operations required by a spatial index to store and retrieve data."]},{"l":"Example","p":["Let's write a simple storage module which stores data in a Map object. The module will be a simple in-memory storage module. The module will be configured with a Map object and will use it to store data."]},{"l":"Store Module","p":["The following code snippet shows the implementation of the storage module."]},{"l":"Store Config","p":["The following code snippet shows the implementation of the store configuration.","And the builder class for the configuration."]},{"l":"Nitrite Store","p":["The following code snippet shows the implementation of the NitriteStore interface."]},{"l":"Nitrite Map","p":["The following code snippet shows the implementation of the NitriteMap interface."]},{"l":"Nitrite RTree","p":["The following code snippet shows the implementation of the NitriteRTree interface."]}],[{"l":"Spatial Module","p":["Nitrite Spatial module provides support for spatial queries. The module uses JTS library for spatial operations."]},{"l":"Adding Spatial Module","p":["Add Spatial module to your project:"]},{"l":"Maven","p":["Add the Spatial dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the Spatial dependency to your build.gradle file:"]},{"l":"Using Spatial Module","p":["To use Spatial module, you need to load the SpatialModule while opening the database.","If Nitrite is using the default SimpleNitriteMapper, then the SpatialModule will automatically register the GeometryConverter with the mapper. If you are using your own custom mapper, then you need to register the GeometryConverter with the mapper."]},{"l":"GeometryConverter","p":["GeometryConverter is an EntityConverter which is used to convert Geometry object of JTS to Document and vice-versa. It is used to store the Geometry object in the database."]},{"l":"Using Spatial Modules with Jackson","p":["If you are using Jackson module for serialization, you need to register the GeometryModule with Jackson as well.","The GeometryModule is required to serialize the Geometry object of JTS via Jackson."]},{"l":"Spatial Index","p":["Spatial module uses R-Tree index to store the spatial data.","To create a spatial index, you need to pass the index type as SpatialIndexer.SPATIAL_INDEX while creating the index.","Spatial index is not supported on multiple fields."]},{"l":"Spatial Filter","p":["Spatial module supports several filters to query spatial data. To know more about filters, please refer to Spatial Filters."]}],[{"l":"Jackson Mapper Module","p":["Nitrite provides a Jackson mapper module to convert Java objects to Document and vice-versa. The module is useful when you don't want to use the EntityConverter interface to map Java objects to Document and vice-versa."]},{"l":"Adding Jackson Mapper Module","p":["Add the Jackson mapper module to your project:"]},{"l":"Maven","p":["Add the Jackson mapper module dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the Jackson mapper module dependency to your build.gradle file:"]},{"l":"Using Jackson Mapper Module","p":["To use Jackson mapper module, you need to load the JacksonMapperModule while opening the database."]},{"l":"Using Custom Jackson Modules","p":["If you want to register any custom Jackson module, you can do so by passing the module to JacksonMapperModule constructor.","If you want to register multiple modules, you can do so by passing an array of modules to JacksonMapperModule constructor.","And here is an example of a custom Jackson module."]},{"l":"Customizing ObjectMapper","p":["If you want to customize the ObjectMapper used by the Jackson mapper module, you can do so by extending the JacksonMapper class and overriding the getObjectMapper() method.","Now, you can use this custom mapper while building the database."]}],[{"l":"Usage","p":["Nitrite provides some additional functionalities via nitrite-support library. You can use the library to enable encryption, import/export database, and database recovery."]},{"l":"Adding nitrite-support","p":["Add the nitrite-support dependency to your project:"]},{"l":"Maven","p":["Add the nitrite-support dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite-support dependency to your build.gradle file:"]}],[{"i":"importexport","l":"Import/Export","p":["Nitrite provides import/export functionality via nitrite-support library. You can import/export your database to/from a file in JSON format. You can choose to import/export the entire database or a specific collection."]},{"l":"Exporting Database","p":["To export the entire database in JSON format, you can use the Exporter class of nitrite-support library. You can construct an instance of Exporter from an ExportOptions instance using Exporter.withOptions() method. The ExportOptions class provides various options to configure the export process.","The exportTo() method can take a File or a String or an OutputStream or a Writer as an argument. If you pass a File or a String argument, the exporter will create a FileOutputStream and write the exported data to the file. If you pass an OutputStream or a Writer argument, the exporter will write the exported data to the stream or writer.","The database must be in closed state before exporting."]},{"l":"Export Options","p":["collections- the list of collections to export. The rules for specifying the collection names are as follows:","exportData- whether to export data or not. It's an optional field, if not provided, it will be set to true.","exportIndices- whether to export indices or not. It's an optional field, if not provided, it will be set to true.","If a non-empty list is specified, only the collections in the list will be exported.","If a non-empty list is specified, only the repositories in the list will be exported.","If a non-empty map is specified, only the keyed repositories in the map will be exported.","If an empty list is specified, no collection will be exported.","If an empty list is specified, no repository will be exported.","If an empty map is specified, no keyed repository will be exported.","If null is specified, all collections will be exported.","If null is specified, all keyed repositories will be exported.","If null is specified, all repositories will be exported.","jsonFactory- the JsonFactory instance to use for export. It is used to create the JsonGenerator instance for export. It's an optional field, if not provided, a default one will be used.","keyedRepositories- the map of keyed repositories to export. The rules for specifying the keyed repository names are as follows:","nitriteFactory- the NitriteFactory instance to use for export. It is used to create the Nitrite instance for export. It's a mandatory field.","repositories- the list of repositories to export. The rules for specifying the repository names are as follows:","The ExportOptions class provides various options to configure the export process. You can set the following options:"]},{"l":"Example","p":["First create a method to create a Nitrite instance, which will be used as the nitriteFactory.","Then create the ExportOptions instance and configure it.","Then create the Exporter instance and export the database.","The test.json file will contain the exported data."]},{"l":"Importing Database","p":["To import the entire database from an exported JSON data, you can use the Importer class of nitrite-support library. You can construct an instance of Importer from an ImportOptions instance using Importer.withOptions() method. The ImportOptions class provides various options to configure the import process.","The importFrom() method can take a File or a String or an InputStream or a Reader as an argument. If you pass a File or a String argument, the importer will create a FileInputStream and read the exported data from the file. If you pass an InputStream or a Reader argument, the importer will read the exported data from the stream or reader.","The database must be in closed state before importing."]},{"l":"Import Options","p":["The ImportOptions class provides various options to configure the import process. You can set the following options:","nitriteFactory- the NitriteFactory instance to use for import. It is used to create the Nitrite instance for import. It's a mandatory field.","jsonFactory- the JsonFactory instance to use for import. It is used to create the JsonParser instance for import. It's an optional field, if not provided, a default one will be used."]},{"i":"example-1","l":"Example","p":["First create a ImportOptions instance and configure it using the createDb() method from the previous example.","Then create the Importer instance and import the database.","The new-test.db file will contain the imported data. You can open the database and use it."]}],[{"l":"Encryption","p":["Nitrite provides encryption support via nitrite-support module. You can encrypt your data using a password. Nitrite provides an Encryptor interface to encrypt and decrypt data. Nitrite also provides an AES based implementation of Encryptor interface, which uses AES/GCM/NoPadding algorithm to encrypt and decrypt data."]},{"l":"Using Encryption","p":["To use encryption, you can either use the AES implementation of Encryptor interface or you can create your own implementation of Encryptor interface."]},{"l":"Using AES Encryptor","p":["To use AES based encryption you need to use the AESEncryptor class. The class takes a password as a parameter in its constructor.","There is another constructor also which takes a password along with the algorithm, tag length, IV length, and salt length.","You can use the encryptor to encrypt and decrypt data."]},{"l":"Using Custom Encryptor","p":["If you want to use your own encryption algorithm, you can do so by implementing the Encryptor interface. The interface has two methods encrypt and decrypt. You can implement these methods to encrypt and decrypt data."]},{"l":"Field Level Encryption","p":["Nitrite provides field level encryption support. You can encrypt a field of a document using a password. Nitrite provides a StringFieldEncryptionProcessor utility class to encrypt and decrypt a field of a document. It is a Processor implementation. It uses the Encryptor interface to encrypt and decrypt data."]},{"l":"Using Field Encryption","p":["To use field encryption, you need to create an instance of StringFieldEncryptionProcessor class. The class takes either an Encryptor instance or a password as a parameter in its constructor.","If you provide the password, the class will create an instance of AESEncryptor class using the password. If you provide an Encryptor instance, the class will use the provided Encryptor instance.","You can also use the AESEncryptor class to create an instance of StringFieldEncryptionProcessor class.","The encrypted data is a base64 encoded string of the encrypted bytes."]}],[{"i":"#","p":["This guide will help you get started with Nitrite database. It will show you how to create a database, create a collection, insert documents, and query documents in Kotlin."]},{"l":"Getting Started in Kotlin","p":["Nitrite's Kotlin SDK is a wrapper around the Java SDK. It provides some Kotlin friendly extensions for some of the Java API to work with Nitrite database. The Kotlin SDK is available as a separate module named potassium-nitrite(KNO 2). In this guide, we will discuss the Kotlin specific API only. For rest of the API, please refer to the Java SDK. So it is highly recommended to go through the Java SDK guide first.","To get started with Nitrite database, you need to add the Nitrite BOM to your project. The BOM will help you to manage the dependencies. Details of the BOM can be found here.","To add the BOM to your project, follow the steps below:"]},{"l":"Add dependency","p":["To enable Kotlin support, you need to add the potassium-nitrite library to your project. It will automatically add the nitrite library as a dependency along with nitrite-spatial and nitrite-jackson-mapper libraries."]},{"l":"Maven","p":["Add the nitrite dependency to your pom.xml file:"]},{"l":"Gradle","p":["Add the nitrite dependency to your build.gradle file:","The latest released version of Nitrite can be found here."]},{"l":"Snapshot builds","p":["Snapshot builds are available from Sonatype.","To use snapshot builds, you need to add the snapshot repository to your pom.xml or build.gradle file:"]},{"i":"maven-1","l":"Maven"},{"i":"gradle-1","l":"Gradle","p":["Nitrite's Kotlin SDK is not as lean as the Java SDK. It has a lot of dependencies. If you are using Kotlin in your project, it is recommended to use the Kotlin SDK. Otherwise, you can use the Java SDK with Kotlin as well."]},{"i":"upgrade-from-3x","l":"Upgrade from 3.x","p":["If you are upgrading from 3.x, please note that there are lots of breaking changes in the API. The whole library is re-written from scratch. It is recommended to go through this guide before upgrading.","You need to use the MVStore as your storage module to upgrade from 3.x. The RocksDB module is not backward compatible.","Nitrite will try to migrate your existing database to the latest version on the provided you are using the MVStore module. If you are using the RocksDB module, you need to migrate your database manually. However, it is recommended to take a backup of your database before upgrading."]}],[{"l":"Nitrite Database","p":["Nitrite database is a serverless, embedded, and self-contained Java NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Creating a Database","p":["Nitrite database can be created in-memory or on-disk. By default, Nitrite database is created in-memory. To create a database on-disk, you need to add a storage module dependency to your project. More details about storage modules can be found here.","To create a database, you need to use nitrite() function. It is a builder function that returns an instance of Nitrite."]},{"l":"In-memory Database","p":["If you don't load any on-disk storage module, then Nitrite will create an in-memory database. The below code snippet shows how to create a database in-memory."]},{"l":"On-disk Database","p":["The below code snippet shows how to create a database on-disk."]},{"l":"MVStore Backed Database","p":["More details about MVStore configuration can be found here."]},{"l":"RocksDB Backed Database","p":["More details about RocksDB configuration can be found here."]},{"l":"Securing a Database","p":["To secure a database, you need to pass a username and password to the nitrite() function. The below code snippet shows how to secure a database.","If you are using a file-based database, then you need to use the same username and password to open the database again. Otherwise, you will get a NitriteSecurityException.","Both username and password must be provided or both must be null."]},{"l":"Registering an EntityConverter","p":["Nitrite database uses a mapper to map Kotlin/Java entities to Nitrite documents and vice-versa. By default, Nitrite uses SimpleNitriteMapper as its mapper. This mapper uses EntityConverter s to map entities to Nitrite documents and vice-versa. To register an EntityConverter, you need to call registerEntityConverter() method on Builder instance.","More details about EntityConverter can be found here."]},{"l":"Loading a Nitrite Module","p":["Nitrite database is modular in nature. It provides a set of modules to extend its functionality. To load a module, you need to call loadModule() method on Builder instance.","More details about Nitrite modules can be found here."]},{"l":"Loading a Storage Module","p":["More details about storage modules can be found here."]},{"l":"Adding Migration Steps","p":["Nitrite database supports migration from one version to another. To add a migration step, you need to call addMigration() method on Builder instance.","More details about schema migration can be found here."]},{"l":"Current Schema Version","p":["To configure the current schema version, you need to set the schemaVersion property on Builder instance.","By default, the initial schema version is set to 1."]},{"l":"Field Separator Character","p":["Nitrite database uses . as the field separator character. It is used to separate nested fields in a document. For example, if you have a document like below:","Then you can access the firstName field like below:","And you can access the street field like below:","To configure the field separator character, you need to set the fieldSeparator property on Builder instance.","By default, the field separator character is set to .."]}],[{"l":"Document","p":["Document is the basic unit of data in Nitrite database. It is a JSON like field-value pairs. The field is always a String and value can be anything including null. Document is schema-less, which means you can store any kind of data in a document.","Nitrite document supports nested document. That means, a value of a field can be another document. This allows you to create complex data structure.","More details on document can be found here."]},{"l":"Kotlin API for Document","p":["Potassium Nitrite provides a set of extension functions to make document manipulation easier."]},{"l":"Create a Document","p":["To create a document, you can use the documentOf function. It takes a vararg of PairString, Any? and returns a Document.","To create a nested document, you can use the documentOf function recursively.","To create an empty document, you can use the emptyDocument function."]},{"l":"Get a Field Value","p":["To get a field value from a document, you can use the index operator [] on the document. It takes a String as the field name and returns the value of the field."]},{"l":"Checking If a Document is Empty","p":["To check if a document is empty, you can use the isEmpty function. It takes no argument and returns a Boolean.","Conversely, to check if a document is not empty, you can use the isNotEmpty function. It takes no argument and returns a Boolean."]}],[{"l":"Nitrite Collection","p":["NitriteCollection represents a named document collection stored in a Nitrite database. It persists documents in a Nitrite database. It is similar to a table in relational database or a collection in MongoDB.","More details on collection can be found here."]},{"l":"Kotlin API for NitriteCollection","p":["Potassium Nitrite provides a higher-order function to make collection manipulation easier."]}],[{"l":"Object Repository","p":["ObjectRepository provides a simple and type-safe API for storing and retrieving Kotlin/Java objects in a Nitrite database. It is built on top of NitriteCollection and provides a similar API for CRUD operations. It also supports indexing and querying. It also supports event based notification on object changes.","More details on repository can be found here."]},{"l":"Kotlin API for ObjectRepository","p":["Potassium Nitrite provides some higher-order functions to make repository manipulation easier."]},{"l":"Creating a Repository with Class Type","p":["You can create a ObjectRepository by passing a class type to getRepository() method."]},{"l":"Creating a Repository with Class Type and Key","p":["You can create a keyed ObjectRepository by passing a class type and a key to getRepository() method.","One typical use case of this keyed repository is to create a repository for each user in a multi-user application. The key can be the user name or user id. This will ensure that each user will have a separate repository for storing objects."]},{"l":"Creating a Repository with EntityDecorator","p":["A ObjectRepository can be created using EntityDecorator. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"Creating a Repository with EntityDecorator and Key","p":["A keyed ObjectRepository can be created using EntityDecorator and a key. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"NitriteMapper","p":["Nitrite provides a mapper interface called NitriteMapper. It is used to map Java objects to Nitrite documents and vice-versa. More details on NitriteMapper can be found here.","Apart from the SimpleNitriteMapper, Potassium Nitrite also provides two additional mappers:","KNO2JacksonMapper","KotlinXSerializationMapper"]},{"l":"Jackson Mapper","p":["Potassium Nitrite extends the JacksonMapper to provide KNO2JacksonMapper. This class overrides the getObjectMapper() method to register some Kotlin specific Jackson modules as follows:","KotlinModule","JavaTimeModule","Jdk8Module","GeometryModule","It also disables the SerializationFeature.WRITE_DATES_AS_TIMESTAMPS feature. The constructor of KNO2JacksonMapper takes a vararg of com.fasterxml.jackson.databind.Module to register additional Jackson modules.","To use the KNO2JacksonMapper instead of the default SimpleNitriteMapper you need to load it while opening the database."]},{"l":"KotlinX Serialization Mapper","p":["Potassium Nitrite also provides a KotlinX Serialization based mapper called KotlinXSerializationMapper. KotlinX Serialization is used to convert Java/Kotlin objects to Document and vice-versa.","To use the KotlinXSerializationMapper instead of the default SimpleNitriteMapper you need to load it while opening the database."]}],[{"l":"Filters","p":["Filters are used to specify the criteria used to select documents from a collection or repository. It provides a way to specify conditions that the documents must meet to be included in the result set. Filters are used in conjunction with the find method. The find method returns all documents in a collection that match the specified filtering criteria.","More details on filters can be found here."]},{"l":"Kotlin API for Filters","p":["Potassium Nitrite provides a set of infix functions to make filter usage more like operators. It also provides a set of extension functions for KProperty so that you can use property name instead of string in case of entity class."]},{"l":"Comparison Operators","p":["Comparison operators are used to compare two expressions. More details on comparison operators can be found here."]},{"l":"Equal To","p":["To check if a field value is equal to a value, you can use the eq function.","Similarly, you can use the eq function with KProperty.","More details on eq function can be found here."]},{"l":"Not Equal To","p":["To check if a field value is not equal to a value, you can use the notEq function.","Similarly, you can use the notEq function with KProperty.","More details on notEq function can be found here."]},{"l":"Greater Than","p":["To check if a field value is greater than a value, you can use the gt function.","Similarly, you can use the gt function with KProperty.","More details on gt function can be found here."]},{"l":"Greater Than or Equal To","p":["To check if a field value is greater than or equal to a value, you can use the gte function.","Similarly, you can use the gte function with KProperty.","More details on gte function can be found here."]},{"l":"Less Than","p":["To check if a field value is less than a value, you can use the lt function.","Similarly, you can use the lt function with KProperty.","More details on lt function can be found here."]},{"l":"Less Than or Equal To","p":["To check if a field value is less than or equal to a value, you can use the lte function.","Similarly, you can use the lte function with KProperty.","More details on lte function can be found here."]},{"l":"Within","p":["To check if a field value is in a list of values, you can use the within function.","Similarly, you can use the within function with KProperty.","You can also use it with range.","More details on within function can be found here."]},{"l":"Not Within","p":["To check if a field value is not in a list of values, you can use the notWithin function.","Similarly, you can use the notWithin function with KProperty.","You can also use it with range.","More details on notWithin function can be found here."]},{"l":"Between","p":["To check if a field value is between two values, you can use the between function. More details on between function can be found here."]},{"l":"Logical Filters","p":["Logical operators are used to combine two or more expressions. More details on logical operators can be found here."]},{"l":"And","p":["To combine two or more expressions with AND operator, you can use the and function.","Similarly, you can use the and function with KProperty.","More details on and function can be found here."]},{"l":"Or","p":["To combine two or more expressions with OR operator, you can use the or function.","Similarly, you can use the or function with KProperty.","More details on or function can be found here."]},{"l":"Array Filters","p":["Array filters are used to match documents based on the values in an array field. More details on array filters can be found here."]},{"l":"Element Match","p":["To check if an array field contains at least one element that matches the specified filter, you can use the elemMatch function.","Similarly, you can use the elemMatch function with KProperty.","More details on elemMatch function can be found here."]},{"l":"Evaluation Filters","p":["Evaluation filters are used to match documents based on evaluating the value of any field in a document. More details on evaluation filters can be found here."]},{"l":"Regex","p":["To check if a field value matches a regular expression, you can use the regex function.","Similarly, you can use the regex function with KProperty.","More details on regex function can be found here."]},{"l":"Text","p":["The text filter is used to match documents which contain a specified full-text search expression.","Similarly, you can use the text function with KProperty.","More details on text function can be found here."]},{"l":"Spatial Filters","p":["Spatial filters are used to match documents based on their geometric shape. More details on spatial filters can be found here."]},{"l":"Near","p":["To check if a field value is near to a point, you can use the near function.","Similarly, you can use the near function with KProperty.","More details on near function can be found here."]},{"i":"within-1","l":"Within","p":["To check if a field value is within a specified shape, you can use the within function.","Similarly, you can use the within function with KProperty.","More details on within function can be found here."]},{"l":"Intersects","p":["The intersects filter is used to match documents where the value of the spatial field intersects the specified shape.","Similarly, you can use the intersects function with KProperty.","More details on intersects function can be found here."]}],[{"l":"Transaction","p":["Nitrite supports transactional operations on its collections and repositories. A transaction can be committed or rolled back. Once a transaction is committed, all the changes are persisted to the disk. If a transaction is rolled back, all the changes are discarded.","More information about Nitrite transactions can be found here."]},{"l":"Kotlin API for Transaction","p":["Potassium Nitrite provides a set of builder functions for Session and Transaction to make transaction usage more like natural to Kotlin."]},{"l":"Session","p":["A session represents a transactional context for a Nitrite database. Session is used to create a new transaction. More details on session can be found here."]},{"l":"Kotlin API for Session","p":["To create a new session, you can use the session() extension function on Nitrite.","Session will be automatically closed once the block is executed."]},{"l":"Transaction","p":["A transaction is a single logical unit of work which accesses and possibly modifies the contents of a database. Transactions access data using read and write operations. More details on transaction can be found here."]},{"i":"kotlin-api-for-transaction-1","l":"Kotlin API for Transaction","p":["To start a transaction, you can use the tx() extension function on Session.","Transaction will be automatically closed once the block is executed."]}],[{"l":"Potassium Nitrite Module","p":["Nitrite is a modular database engine, so is Potassium Nitrite. All Nitrite modules are compatible with Potassium Nitrite as well. More details about Nitrite modules can be found here.","Potassium Nitrite provides a single module KNO2Module to load all plugins it provides. You can load the module while opening the database.","This module loads the following plugins:","KNO2JacksonMapper- A Jackson based mapper for Potassium Nitrite.","SpatialIndexer- A spatial index plugin for Nitrite.","Visit the respective pages to know more about the plugins."]}],[{"i":"#","p":["This guide will help you get started with Nitrite database. It will show you how to create a database, create a collection, insert documents, and query documents in Flutter."]},{"l":"Getting Started in Flutter","p":["Nitrite is a pure Dart database. It does not depend on any native library. So it can be used in any platform where Dart is supported. It is a server-less embedded database ideal for desktop, mobile, or web applications. It is written in pure Dart and runs in Flutter, Dart VM, and the browser."]},{"l":"Add dependency","p":["To use Nitrite in you project, add the following package to your package:","To add the nitrite code generator to your project:","More details about the code generator can be found here.","To use the hive storage adapter to your project add the below package:","More details about the hive adapter can be found here.","Nitrite is null safe. So you can use it in your null safe project."]}],[{"l":"Database","p":["Nitrite database is a serverless, embedded, and self-contained database for Flutter. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use."]},{"l":"Creating a Database","p":["Nitrite database can be created in-memory or on-disk. By default, Nitrite database is created in-memory. To create a database on-disk, you need to add a storage module dependency to your project. More details about storage modules can be found here.","To create a database, you need to use NitriteBuilder class. To get an instance of NitriteBuilder, you need to call builder() method on Nitrite class."]},{"l":"In-memory Database","p":["If you don't load any on-disk storage module, then Nitrite will create an in-memory database. The below code snippet shows how to create a database in-memory."]},{"l":"On-disk Database","p":["The below code snippet shows how to create a database on-disk."]},{"l":"Hive Backed Database","p":["More details about Hive configuration can be found here."]},{"l":"NitriteBuilder","p":["NitriteBuilder is the builder class for Nitrite database. It provides methods to configure and create a Nitrite database instance."]},{"l":"Open or Create a Database","p":["To open or create a database, you need to call openOrCreate() method on NitriteBuilder instance. This method returns a FutureNitrite instance.","If no StoreModule is configured, then Nitrite will create an in-memory database. If a StoreModule is configured, then Nitrite will create an on-disk database. If the database file does not exist, then Nitrite will create a new database file. If the database file exists, then Nitrite will open the database file."]},{"l":"Securing a Database","p":["To secure a database, you need to call openOrCreate() method with username and password on NitriteBuilder instance. This method returns a FutureNitrite instance with the given username and password.","If you are using a file-based database, then you need to use the same username and password to open the database again. Otherwise, you will get a NitriteSecurityException.","Both username and password must be provided or both must be null."]},{"l":"Registering an EntityConverter","p":["Nitrite database uses a mapper to map a Dart object to a document and vice versa. By default, Nitrite uses SimpleNitriteMapper as its mapper. This mapper uses EntityConverter s to map a Dart object to a document and vice versa. To register an EntityConverter, you need to call registerEntityConverter() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More details about EntityConverter can be found here."]},{"l":"Loading a Module","p":["Nitrite database is modular in nature. It provides various modules to extend its functionality. To load a module, you need to call loadModule() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance."]},{"l":"Loading a Storage Module","p":["More on the Nitrite's module system can be found here."]},{"l":"Adding Migration Steps","p":["Nitrite database supports schema migration. To configure a migration step, you need to call addMigrations() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","More on the schema migration can be found here."]},{"l":"Current Schema Version","p":["To get the current schema version of a database, you need to call schemaVersion() method on NitriteBuilder instance. This method returns the current schema version of the database.","By default, the initial schema version is set to 1."]},{"l":"Field Separator Character","p":["To configure the field separator character, you need to call fieldSeparator() method on NitriteBuilder instance. This method returns the same NitriteBuilder instance.","It is used to separate field names in a nested document. For example, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax.","The default field separator character is set to .."]}],[{"l":"Document","p":["Document is the basic unit of data in Nitrite database. It is a JSON like field-value pairs. The field is always a String and value can be anything including null. Document is schema-less, which means you can store any kind of data in a document.","Nitrite document supports nested document. That means, a value of a field can be another document. This allows you to create complex data structure."]},{"l":"Document Structure","p":["Nitrite document has the following structure."]},{"l":"Document Field","p":["Document field is always a String. It can be any valid string. The field cannot be null or empty string.","Below fields are reserved and cannot be used as key in a document.","_id: The unique identifier of a document. This field is auto-generated by Nitrite database during insertion.","_revision: The revision number of a document. This field is auto-generated by Nitrite database during insertion and update.","_source: The source collection name of a document.","_modified: The last modified timestamp of a document. This field is auto-generated by Nitrite database during insertion and update."]},{"l":"Document Value","p":["Document value can be any valid Dart object. It can be null or any of the below types.","String","int","double","bool","List","Map","Set","DateTime","NitriteId","Document"]},{"l":"Document Identifier","p":["It is a unique identifier of a document. It is auto-generated by Nitrite database during insertion. It is a NitriteId and is stored as a String in the document."]},{"l":"NitriteId","p":["NitriteId is a unique identifier across the Nitrite database. Each document in a nitrite collection is associated with a NitriteId.","During insertion if a unique String value representing a integer is supplied in the _id field of the document, then the value of the _id field will be used to generate the NitriteId. Otherwise, a new NitriteId will be generated and will be used in the _id field of the document.","The value of the NitriteId is a String representation of a 64-bit integer. The id generation is based on Twitter Snowflake algorithm. The id is composed of:","41 bits for time in milliseconds","10 bits for a machine id","12 bits for a sequence number","1 unused sign bit","The id is not guaranteed to be monotonically increasing. The id is sortable and the timestamp is stored in the id itself."]},{"l":"Retrieving a NitriteId from a Document","p":["The id can be retrieved from a document using Document.id getter. If the document does not have an id, then it will create a new NitriteId and will set it in the document and will return the id. If the document already has an id, then it will return the id."]},{"l":"Field Separator","p":["To access a field of a nested document, or an element of an array field, you need to use the field separator.","Field separator is configurable. You can change the field separator character by calling NitriteBuilder.fieldSeparator() method.","Nitrite uses . as field separator by default."]},{"l":"Nested Document","p":["To specify or access a field of a nested document, you need to use the field separator character. That means, if a document has a field address which is a nested document, then the field street of the nested document can be accessed using address.street syntax."]},{"l":"Array Field","p":["To specify or access an element of an array field, you need to use the index of the element. For example, if a document has a field phone which is an array, then the first element of the array can be accessed using phone.0 syntax."]},{"l":"Creating a Document","p":["To create a document, you need to use createDocument() function."]},{"l":"Creating an Empty Document"},{"l":"Creating a Document with Initial Field-value Pair"},{"l":"Creating a Document with a Map"},{"l":"Updating a Document","p":["To update a document, you need to use Document.put() method. This method takes two parameters, the field name and the value. If the field already exists in the document, then the value will be updated. If the field does not exist, then it will be created.","You can also use the [] operator to update a document."]},{"l":"Retrieving a Value from Document","p":["To retrieve a value from document, you need to use Document.get() method. This method takes one parameter, the field name. If the field exists in the document, then the value will be returned. If the field does not exist, then it will return null.","You can also use the [] operator to retrieve a value from a document.","To retrieve a value from a nested document, use the field separator character.","To retrieve an element from an array field, use the index of the element."]},{"l":"Removing a Field from Document","p":["To remove a field from document, you need to use Document.remove() method. This method takes one parameter, the field name. If the field exists in the document, then it will be removed. If the field does not exist, then it will do nothing.","To remove a field from a nested document, use the field separator character.","To remove an element from an array field, use the index of the element."]},{"l":"Checking If a Field Exists in Document","p":["To check if a field exists in a document, you need to use Document.containsKey() method. This method takes one parameter, the field name. If the field exists in the document, then it will return true. If the field does not exist, then it will return false.","To check if a field exists in a nested document, use the field separator character.","It cannot check if an element exists in an array field."]}],[{"l":"Introduction","p":["NitriteCollection represents a named document collection stored in a Nitrite database. It persists documents in a Nitrite database. It is similar to a table in relational database or a collection in MongoDB.","Each document in a collection is associated with a unique NitriteId. It exposes a set of methods to perform CRUD operations on documents. It also supports indexing and querying. It also supports event based notification on document changes."]},{"l":"Creating a Collection","p":["A NitriteCollection can be created using Nitrite class. You need to call getCollection() method on Nitrite class to get an instance of a FutureNitriteCollection.","If the collection does not exist, then it will be created automatically. If a collection with the same name already exists, then it will return the existing collection."]},{"l":"Limitations on Collection Name","p":["A collection name cannot be null or empty string. It cannot contains any of the following characters:","|(pipe)",":(colon)","+(plus)","The name also cannot be any of the following reserved words:","$nitrite_users","$nitrite_index_meta","$nitrite_index","$nitrite_meta_map","$nitrite_store_info","$nitrite_catalog"]}],[{"l":"Write Operations"},{"l":"Inserting Documents","p":["Documents can be inserted into a collection using insert() or insertMany() methods. It takes one or multiple Document objects as input parameter respectively. It returns a FutureWriteResult object.","If the document has a NitriteId already in it's _id field, then it will be used as a unique key to identify the document in the collection. Otherwise, a new NitriteId will be generated and inserted into the document.","If any of the field is already indexed in the collection, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.insert event."]},{"l":"Inserting a Single Document"},{"l":"Inserting Multiple Documents"},{"l":"Error Scenarios","p":["If the document contains invalid value in it's _id field, then it will throw a InvalidIdException.","If there is another document with the same _id value in the collection, then it will throw a UniqueConstraintException.","If a field of the document is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["WriteResult contains the result of a write operation. It contains the following information:","Number of documents affected by the write operation. You can get this value using getAffectedCount() method.","List of NitriteId of the documents affected by the write operation. The WriteResults implements IterableNitriteId interface. So you can iterate over the WriteResult to get the NitriteId of the documents affected by the write operation."]},{"l":"Updating Documents","p":["Documents can be updated using any of the following methods:","updateOne()- Updates a single document.","update()- Update the filtered documents in the collection.","All update methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.update event."]},{"l":"Updating a Single Document","p":["You can update a single document using updateOne() method. It takes a Document object as input parameter. It returns a FutureWriteResult object. The document must contain a valid NitriteId in it's _id field.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Document","p":["You can also upsert a single document using updateOne() method. Along with the document parameter, you need to pass a named parameter insertIfAbsent with value true. If the document does not exist in the collection, then it will be inserted. Otherwise, it will be updated. The default value of insertIfAbsent is false."]},{"l":"Updating Using a Filter","p":["You can update multiple documents using a filter. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It returns a FutureWriteResult object."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a Document object as the second input parameter. It takes a UpdateOptions object as the optional third input parameter. It returns a FutureWriteResult object."]},{"l":"UpdateOptions","p":["UpdateOptions is a class that contains several options for update operation. It has the following options:","insertIfAbsent: If this option is true, then it will insert the document if it does not exist in the collection. Otherwise, it will update the document if it exists in the collection.","justOnce: If this option is true, then it will update only the first document matched by the filter. Otherwise, it will update all the documents matched by the filter."]},{"l":"Removing Documents","p":["Documents can be removed from a collection using any of the following methods:","removeOne()- Removes a single document.","remove()- Removes the filtered documents from the collection.","All remove methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.remove event."]},{"l":"Removing a Single Document","p":["You can remove a single document using removeOne() method. It takes a Document object as input parameter. It returns a FutureWriteResult object. The document must contain a valid NitriteId in it's _id field.","If the document does not contain a valid NitriteId in it's _id field, then it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple documents using a filter. It takes a Filter object as the input parameter. It returns a FutureWriteResult object."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple documents using a filter and options. It takes a Filter object as the first input parameter. It takes a named parameter justOne with value true or false. If the value is true, then it will remove only the first document matched by the filter. Otherwise, it will remove all the documents matched by the filter. The default value of justOne is false. It returns a FutureWriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["You can search documents in a collection using find() method. There are several ways of using find() method using a filter or find options or both. You can also search a document using it's NitriteId."]},{"l":"Filters","p":["Nitrite uses filters to find documents in a collection. A filter is a simple expression which evaluates to true or false. More information about filters can be found here."]},{"l":"Find All Documents","p":["You can find all documents in a collection by calling find(). It returns a DocumentCursor object."]},{"l":"Finding a Document Using NitriteId","p":["You can find a document using it's NitriteId by calling getById(). It takes a NitriteId as input parameter. It returns a FutureDocument? object if the document is found. Otherwise, it returns null."]},{"l":"Finding a Document Using a Filter","p":["You can find a document using a filter. It takes a Filter object as input parameter. It returns a DocumentCursor object.","If there is an index on the field specified in the filter, this operation will use the index to find the document. Otherwise, it will scan the entire collection to find the document."]},{"l":"Finding a Document Using a Filter and Options","p":["You can find a document 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 DocumentCursor object."]},{"l":"FindOptions","p":["FindOptions is a class that contains several options for find operation. It has the following options:","limit: It specifies the maximum number of documents to be returned by the find operation.","skip: It specifies the number of documents to be skipped from the beginning of the result set.","orderBy: It specifies a collection of fields to be sorted by, along with sort order for each field. The sort order can be SortOrder.ascending or SortOrder.descending.","distinct: It specifies if the find operation should return distinct documents. If this option is true, then it will return only the distinct documents. Otherwise, it will return all the documents matched by the filter."]},{"l":"DocumentCursor","p":["DocumentCursor represents a result set of a find operation. It provides methods to iterate over the result of a find operation and retrieve the documents. It also provides methods like projection, join etc. to get the desired result."]},{"l":"Iterating Over Documents","p":["The DocumentCursor extends StreamDocument. So, you can iterate over the documents using await for loop.","A DocumentCursor is a stream of document. It does not load all the documents in memory at once. It loads the documents in memory as needed. So, it is memory efficient."]},{"l":"Getting the Documents","p":["You can get the documents from a DocumentCursor using toList() method. It returns a FutureListDocument object."]},{"l":"Getting the First Document","p":["You can get the first document from a DocumentCursor using first getter. It returns a FutureDocument? object."]},{"l":"Getting the Size of the Result Set","p":["You can get the size of the result set from a DocumentCursor using length getter. It returns a Futureint object."]},{"l":"Projection","p":["You can project a field or a set of fields from a DocumentCursor using project() method. It takes a Document as input parameter. It returns a StreamDocument object.","The document must contain only the fields that needs to be projected. The field values must be null or a nested document. The condition holds true for nested documents as well.","Let's say you have a document like this:","And you want to project only lastName and address.street fields. Then you can do it like this:","The result set will contain only lastName and address.street fields."]},{"l":"Join","p":["You can join two DocumentCursor using leftJoin() method. It takes another DocumentCursor as input parameter along with a Lookup object. It returns a StreamDocument object.","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 collections users and orders. The users collection contains the following documents:","And the orders collection contains the following documents:","And you want to join these two collections on userId field. Then you can do it like this:","The result set will contain the following documents:"]},{"l":"FindPlan","p":["FindPlan is a class that contains the execution plan of a find operation. It has the following properties:","byIdFilter: It contains the filter for finding a document using NitriteId.","indexScanFilter: It contains the filter for finding a document using index.","collectionScanFilter: It contains the filter for finding a document using full scan.","indexDescriptor: It contains the index descriptor for finding a document using index.","indexScanOrder: It contains the sort order for finding a document using index.","blockingSortOrder: It contains the sort order for finding a document using full scan.","skip: It contains the number of documents to be skipped from the beginning of the result set.","limit: It contains the maximum number of documents to be returned by the find operation.","distinct: It specifies if the find operation returns distinct documents.","subPlans: It contains the sub plans for finding a document using or filter.","You can get the execution plan of a find operation using findPlan getter. It returns a FutureFindPlan object."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a collection. It supports indexing on a single field or multiple fields. It also supports full-text indexing."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in a document. It is useful when you want to search text content in a document. It is also useful when you want to search text content in a document in a language other than English.","Document's _id field is always indexed.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. You need to implement NitriteIndexer interface to create your own custom index. NitriteIndexer is a NitritePlugin, so you need to register it using loadModule() method while opening a database. During index creation you need to pass the type of the custom index in IndexOptions object.","One of such custom index implementation can be found in spatial module. It provides spatial indexing on a collection. More on spatial indexing can be found here."]},{"l":"Creating an Index","p":["You can create an index on a collection using createIndex() method. There are several overloaded version of createIndex() method. You can create an index on a single field or multiple fields."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.nonUnique in IndexOptions object and the name of the fields on which the index will be created as input parameters."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field by passing the index type as IndexType.fullText in IndexOptions object and the name of the fields on which the index will be created as input parameters.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Array Field","p":["Nitrite supports creating index on array field. It will create index on each element of the array. For example, if you have a document like this:","You can create index on phones field like this:"]},{"l":"Creating Index on Nested Field","p":["You can create index on nested field. For example, if you have a document like this:","You can create index on street field like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index on a collection using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index on a collection using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes on a collection using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes on a collection using listIndices() method. It returns a FutureCollection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a simple class which contains the following information about an index:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists on a collection using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the collection on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Collection","p":["You can get the size of a collection using size getter. It returns a future of the number of documents in the collection."]},{"l":"Clearing a Collection","p":["You can clear all the documents from a collection using clear() method. It removes all the documents from the collection and index entries from the indexes. It does not drop the collection."]},{"l":"Dropping a Collection","p":["You can drop a collection using drop() method. It removes all the documents from the collection and index entries from the indexes. It also drops all the indexes associated with the collection. It also removes the collection from the database.","You can call isDropped getter to check if the collection is dropped or not.","Any further operation on a dropped collection will throw NitriteIOException."]},{"l":"Closing a Collection","p":["You can close a collection using close() method. Any further operation on a closed collection will throw NitriteIOException.","After closing a collection, you must re-open it via Nitrite.getCollection() method to perform any operation on it.","You can call isOpen getter to check if the collection is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a collection to get notified on document changes. The event listener must implement CollectionEventListener interface. It will receive CollectionEventInfo whenever a document is inserted, updated or removed from the collection.","You can also remove an event listener from a collection."]},{"l":"CollectionEventInfo","p":["CollectionEventInfo contains the following information:","item- the document which is inserted, updated or removed.","originator- the name of the collection on which the event is fired.","eventType- the type of the event. It can be any of the following:","EventType.insert","EventType.update","EventType.remove","EventType.indexStart","EventType.indexEnd","timestamp- the timestamp of the event."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a collection.","You can get/set attributes on a collection. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processors are used to process documents before writing them into or after reading them from a collection.","Processors are useful when you want to add some additional information in a document or transform any field before inserting or updating it in a collection. Processors are also useful when you want to validate a document before inserting or updating it in a collection.","Processors are registered on a collection. A collection can have multiple processors. Processors are executed in the order they are registered."]},{"l":"Registering a Processor","p":["You can register a processor on a collection using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a collection and decrypt a field after reading it from a collection.","More on this is described in Support."]}],[{"l":"Introduction","p":["ObjectRepository provides a simple and type-safe API for storing and retrieving Dart objects in a Nitrite database. It is built on top of NitriteCollection and provides a similar API for CRUD operations. It also supports indexing and querying. It also supports event based notification on object changes."]},{"l":"Creating a Repository","p":["An ObjectRepository can be created using Nitrite class. You need to call getRepository() method on Nitrite class to get an instance of an ObjectRepository. If the repository does not exist, then it will be created automatically. If a repository with the same name already exists, then it will return the existing repository.","There are several options available to create a repository. You can pass a class type or an EntityDecorator along with an optional string key to create a repository."]},{"l":"Creating a Repository with Class Type","p":["You can create a ObjectRepository by passing a class type to getRepository() method."]},{"l":"Creating a Repository with Class Type and Key","p":["You can create a keyed ObjectRepository by passing a class type and a key to getRepository() method.","One typical use case of this keyed repository is to create a repository for each user in a multi-user application. The key can be the user name or user id. This will ensure that each user will have a separate repository for storing objects."]},{"l":"Creating a Repository with EntityDecorator","p":["A ObjectRepository can be created using EntityDecorator. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]},{"l":"Creating a Repository with EntityDecorator and Key","p":["A keyed ObjectRepository can be created using EntityDecorator and a key. This is useful when you cannot modify the object class to add annotations.","More details about EntityDecorator can be found here."]}],[{"l":"Code Generator","p":["Nitrite provides Dart build system builders to extract metadata and generate code for entity classes which is used by ObjectRepository. The builders generate code when they find a class annotated with some Nitrite specific annotations. The generated code is written to a file that is named after the source file, but with .no2.dart extension.","Flutter doesn't support reflection, so the generated code is used to extract metadata and generate code for entity classes.","There are two generators available:","Entity Generator- Extracts metadata from classes annotated with @Entity and generates code for entity classes.","Converter Generator- Scans the classes annotated with @Convertable and generates the code to convert the Dart classes to Nitrite documents and vice-versa.","Both of these generators are available in the nitrite_generator package."]},{"l":"Setup","p":["Add the following package as your dev dependency:","Once you have added the annotations to your code, you can run the generator using the build_runner command-line tool:"]},{"l":"Annotations for Entity Generator","p":["The following annotations are used by the entity generator:","@Entity- Marks a class as an entity class.","@Id- Marks a field as the primary key of the entity.","@Index- Provides index information for entity fields.","More on each of these annotations is here."]},{"l":"Annotations for Converter Generator","p":["The following annotations are used by the converter generator:","@Convertable- Generates the EntityConverter for the class.","@DocumentKey- Specifies the name of the field in the document.","@IgnoredKey- Marks a field as ignored while converting to document.","More on each of these annotations is here."]},{"l":"Examples","p":["Consider a book entity class and it's generated code:"]},{"l":"Limitations","p":["There are certain limitations of each of the generators as described below:"]},{"l":"Entity Generator","p":["@Entity annotation can only be used on a class.","@Id annotation can only be used on a field and once per class.","@Id field should be one of the following data types:","num","int","double","String","Runes","bool","DateTime","Duration","NitriteId","A class in case of embedded id.","@Id field should not be static or synthetic."]},{"l":"Converter Generator","p":["@Convertable annotation can only be used on a class and not on an abstract class or mixin.","@Convertable can only be used on a class which has at least one public constructor which is either a default constructor or one with all the parameters named or optional. Examples are given below.","@DocumentKey annotation can not be used on a private/static/synthetic field.","@DocumentKey, @IgnoredKey annotation can only be used on a field or property.","@IgnoredKey annotation can not be used on a field with the same name as a non-null required named parameter in the constructor.","A class with a constructor having all named parameters (optional/required) should have all the fields' names same as the parameter names.","A class with a constructor having all positional optional parameters should not have any final field.","A getter must be defined for corresponding setter or vice-versa.","dynamic type is not supported.","Function types are not supported.","If any of the above limitations are not met, then the generator will throw an exception and the build will fail.","Nested collection is not supported.","Never type is not supported.","Symbol type is not supported.","There are certain limitations on the fields and its data types:","Void type is not supported."]}],[{"l":"Entity","p":["An entity is a Dart object that can be stored in a collection. An entity can be a simple class with a few fields or a complex class with nested objects. Every entity in an ObjectRepository is actually converted to a Document before storing in the underlying NitriteCollection. When an entity is converted to a Document, the fields of the entity are mapped to the fields of the Document. While retrieving an entity from the ObjectRepository, the Document is converted back to the entity.","Nitrite uses a NitriteMapper implementation to convert an entity to a Document and vice versa. By default, Nitrite uses an EntityConverter based implementation of NitriteMapper to convert an entity to a Document. You can also provide your own implementation of NitriteMapper to convert an entity to a Document.","More on NitriteMapper can be found here."]},{"l":"Annotations","p":["Nitrite uses annotations to define an entity. There are several annotations available to define an entity. These annotations are:","@Entity","@Id","@Index","Flutter does not support reflection. So, Nitrite uses code generators to process these annotations and generates the metadata for an entity. The entity generator generates a mixin for an entity class in a separate file that is named after the source file, but with .no2.dart extension.","The name of the mixin is like - _$+ ClassName+ EntityMixin. For example, if the entity class name is Person, the mixin name will be _$PersonEntityMixin. The generated mixin also implements NitriteEntity interface which defines few getters to access the metadata of the entity. You need to add this mixin to your entity class to make it a Nitrite entity.","The entity generator is a separate package and more on the entity generator can be found here."]},{"i":"entity","l":"@Entity","p":["The @Entity annotation marks a class as an entity class. The annotation has the following properties:","name- The name of the collection to which the entity belongs. If not specified, the name of the class is used as the collection name.","indices- An array of @Index annotations. The indices are created on the fields specified in the @Index annotation.","The above code generates the following code in book.no2.dart:","Now you can use the generated mixin in your entity class:"]},{"i":"id","l":"@Id","p":["The @Id annotation marks a field as the unique identifier of the entity. It is a field level annotation and takes optional fieldName parameter. The fieldName parameter is used to specify the name of the field in the document. If the fieldName parameter is not specified, then the name of the field in the class will be used as the name of the field in the document.","The above code generates the following code in book.no2.dart:"]},{"l":"Embedded Id","p":["Nitrite also supports embedded id. The embedded id is used when the entity has a composite primary key. The @Id annotation can also be used to mark a field as an embedded id. In case of embedded id, the field should be marked with @Id annotation and the fieldName and embeddedFields parameters should be specified. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","The above code generates the following code in book.no2.dart:","The above @Id annotation will create a unique compound index on the fields - book_id.isbn and book_id.title."]},{"l":"Data Type","p":["The data type of the field marked with @Id annotation should be one of the following:","num","int","double","String","Runes","bool","DateTime","Duration","NitriteId","In case of embedded id, the data type of the field marked with @Id annotation should be a class."]},{"i":"index","l":"@Index","p":["@Index annotation is used to declare an index on an entity field. It is a class level annotation and takes mandatory fields parameter and optional type parameter. The fields parameter is used to specify the names of the fields in the document to be indexed. The type parameter is used to specify the type of the index. If the type parameter is not specified, then the type of the index will be IndexType.unique.","The above code generates the following code in book.no2.dart:","The above @Index annotations will create the following indices:","tags- Non-unique simple index","description- Full-text index","price and publisher- Unique compound index","@Index annotation can be used on super class as well. When the entity class extends a super class, the @Index annotations of the super class are also processed by the entity generator."]},{"l":"EntityDecorator","p":["EntityDecorator is used to add metadata to an entity. If you cannot modify the entity class to add annotations, then you can use EntityDecorator to add metadata to an entity. You can use EntityDecorator to add id, indices and collection name for an entity.","While creating or opening a repository, you can pass an instance of EntityDecorator to the getRepository() method on Nitrite class. Nitrite will extract the metadata from the EntityDecorator instance and use it to create the repository.","To write an EntityDecorator for an entity, you need to implement the EntityDecorator interface. Let's take an example of a Product entity.","The Product entity has an embedded id ProductId and two indices on a nested object Manufacturer. To write an EntityDecorator for the Product entity with collection name 'products', you need to implement the EntityDecorator interface as follows.","which is equivalent to the following entity class when code generator is used:"]},{"l":"EntityId","p":["EntityId is used to specify the id field of an entity. It takes mandatory fieldName parameter and optional embeddedFields parameter in case of embedded id. The fieldName parameter is used to specify the name of the field in the document. The embeddedFields parameter is used to specify the name of the fields in the embedded object.","Here productId is the name of the field in the document and uniqueId and productCode are the names of the fields in the embedded object. This will create a unique compound index on the fields - productId.uniqueId and productId.productCode."]},{"l":"EntityIndex","p":["EntityIndex is used to specify the indices on an entity. It takes mandatory type parameter and fields parameter. The type parameter is used to specify the type of the index. The fields parameter is used to specify the name of the fields in the document to be indexed.","Here manufacturer.name is the name of the field in the document and productName and manufacturer.uniqueId are the names of the fields in the document. This will create a non-unique index on the field manufacturer.name and a unique compound index on the fields - productName and manufacturer.uniqueId."]},{"l":"Entity Name","p":["Entity name is used to specify the name of the collection in which the entity will be stored. It is a string value and can be specified using entityName getter.","Here products is the name of the NitriteCollection in which the product document will be stored."]}],[{"l":"NitriteMapper","p":["NitriteMapper is a simple and lightweight object mapper which can be used to map Dart objects to Nitrite documents and vice-versa. Nitrite uses a NitriteMapper implementation to map Dart entities to Nitrite documents and vice-versa while storing and retrieving objects from an ObjectRepository."]},{"l":"SimpleNitriteMapper","p":["Nitrite provides a default NitriteMapper implementation called SimpleNitriteMapper. This is a simple and lightweight mapper which uses EntityConverter to map a Dart object to Nitrite documents and vice-versa. This mapper is suitable for most of the use cases."]},{"l":"EntityConverter","p":["EntityConverter is a simple interface which provides methods to convert a Dart object to Nitrite document and vice-versa. For each Dart class, you need to provide an implementation of EntityConverter and register it with SimpleNitriteMapper. SimpleNitriteMapper will use this converter to map the Dart object to Nitrite document and vice-versa.","You can write your own implementation of EntityConverter or you can use the code generator to generate the implementation for you. More on this is discussed here.","Let's take an example of Product class.","To map to Nitrite document, we need to provide an implementation of EntityConverter for each class. Let's take a look at the converter for Product class.","Similarly, we need to provide converters for ProductId and Manufacturer classes.","Once the converters are ready, we need to register them with registerEntityConverter() method on NitriteBuilder instance.","we can also register the converters with SimpleNitriteMapper instance and then pass the instance to loadModule() method.","NitriteMapper is a NitritePlugin. So, you need to load it using loadModule() method on NitriteBuilder. More on Nitrite's module system can be found here.","If you have used the registerEntityConverter() method on NitriteBuilder instance, Nitrite will only use SimpleNitriteMapper to map the entities. It will ignore any other NitriteMapper implementation you have provided using loadModule() method."]},{"l":"Mapping Collections","p":["The EntityConverter interface provides some static methods to convert a collection of Dart objects to a collection of Nitrite documents and vice-versa.","These methods are:","fromList()- Converts a List of Dart objects to a List of Nitrite documents. If the type of the elements is a registered value type, it will return the same list without any conversion.","fromIterable()- Converts an Iterable of Dart objects to a List of Nitrite documents. If the type of the elements is a registered value type, it will return the same list without any conversion.","fromSet()- Converts a Set of Dart objects to a Set of Nitrite documents. If the type of the elements is a registered value type, it will return the same set without any conversion.","fromMap()- Converts a Map of key-value pair to a Map of Nitrite documents. If the type of the key or the value is a registered value type, it will not convert those objects to Nitrite document and return as is.","toList()- Converts a List of Nitrite documents to a List of Dart objects.","toIterable()- Converts an Iterable of Nitrite documents to an List of Dart objects.","toSet()- Converts a Set of Nitrite documents to a Set of Dart objects.","toMap()- Converts a Map of Nitrite documents to a Map of key value pair.","These methods are useful when you have a collection of objects as a property of a Dart class."]},{"l":"Example","p":["Let's take an example of Company class which has a map of Employee as a property.","To map this to Nitrite document, we need to provide an implementation of EntityConverter for Company class."]},{"l":"Code Generation","p":["Nitrite provides a code generator to generate the EntityConverter implementation for you. You have to annotate the class with some specific annotations and then run the code generator. The generated code will be saved in a separate file. You still need to register the generated converter with Nitrite.","The code generator is a separate package and more on the entity generator can be found here.","Nitrite uses below annotations to generate the EntityConverter implementation.","@Convertable","@DocumentKey","@IgnoredKey"]},{"i":"convertable","l":"@Convertable","p":["@Convertable annotation is used to mark a class as convertable. This annotation is mandatory for the code generator to work. This annotation specifies the code generator to generate the EntityConverter implementation for the class. It takes an optional parameter className which is used to specify the name of the converter class. If this parameter is not specified, then the code generator will use the class name with Converter suffix as the converter class name.","This will generate the following code:","You need to register the generated converters with Nitrite by calling registerEntityConverter() method on NitriteBuilder instance."]},{"i":"documentkey","l":"@DocumentKey","p":["@DocumentKey annotation is used to mark a field as a document key. This annotation provides an alias to the field. Normally the field name is used as the key in the Nitrite document. If you want to use a different name, then you can specify the alias using this annotation. This annotation can be used on a field or a getter/setter method.","This will generate the following code:"]},{"i":"ignoredkey","l":"@IgnoredKey","p":["@IgnoredKey annotation is used to mark a field as ignored. This annotation is useful when you want to ignore a field while mapping to Nitrite document. This annotation can be used on a field or a getter/setter method.","This will generate the following code:","The code generator imposes some limitations on the Dart classes. These limitations are discussed here."]},{"l":"Custom NitriteMapper","p":["Apart from SimpleNitriteMapper, you can also provide your own implementation of NitriteMapper. You need to implement NitriteMapper interface and provide your own implementation. Once the implementation is ready, you need to load it using loadModule() method on NitriteBuilder while building the database."]}],[{"l":"Write Operations"},{"l":"Inserting Entities","p":["Entities can be inserted into a repository using insert() or insertMay() method. It takes one or multiple Dart entities as input parameter respectively. It returns a future of WriteResult object.","If the entity has a NitriteId field, then the field value would be populated with a new NitriteId before inserting into the repository.","If any of the field is already indexed in the repository, then the index will be updated accordingly.","This operation will notify all the registered CollectionEventListener with EventType.insert event."]},{"l":"Inserting a Single Entity"},{"l":"Inserting Multiple Entities"},{"l":"Error Scenarios","p":["If a field of the entity is unique indexed and it's value violates the index constraint, then it will throw a UniqueConstraintException."]},{"l":"WriteResult","p":["More information about WriteResult can be found here."]},{"l":"Updating Entities","p":["Entities can be updated using any of the following methods:","updateOne()- updates a single entity","update()- updates multiple entities using a filter and update entity","updateDocument()- updates multiple entities using a filter and update document","All update methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.update event."]},{"l":"Updating a Single Entity","p":["You can update a single entity using updateOne() method. It takes a Dart entity as input parameter. It returns a FutureWriteResult object. The entity must have a valid id field.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the idField getter must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Upserting a Single Entity","p":["You can also upsert a single entity using updateOne() method. Along with the entity parameter, you need to pass a named parameter insertIfAbsent with value true. If the entity does not exist in the repository, then it will be inserted. Otherwise, it will be updated. The default value of insertIfAbsent is false."]},{"l":"Updating Using a Filter","p":["You can update multiple entities using a filter. It takes a Filter object as first input parameter. It takes a Dart entity as second input parameter. It returns a FutureWriteResult object.","If the filter result matches multiple entities, then all the entities will be updated."]},{"l":"Updating Using a Filter and Options","p":["You can update multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a Dart entity as second input parameter. It takes a UpdateOptions object as third input parameter. It returns a FutureWriteResult object."]},{"l":"UpdateOptions","p":["More information about UpdateOptions can be found here."]},{"l":"Updating Using a Filter and Document","p":["You can update multiple entities using a filter. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It returns a FutureWriteResult object.","If the filter result matches multiple entities, then all the entities will be updated. The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"i":"updating-using-a-filter-document-and-options","l":"Updating Using a Filter, Document and Options","p":["You can update multiple entities using a filter, document and options. It takes a Filter object as first input parameter. It takes a Document object as second input parameter. It takes a boolean value as third input parameter. If the third input parameter is true, then it will only update the first entity matched by the filter. Otherwise, it will update all the entities matched by the filter. It returns a FutureWriteResult object.","The document must contain only the fields that needs to be updated.","The document should not contain _id field."]},{"l":"Removing Entities","p":["Entities can be removed using any of the following methods:","removeOne()- removes a single entity","remove()- removes multiple entities using a filter","All remove methods returns a FutureWriteResult object.","This operation will notify all the registered CollectionEventListener with EventType.remove event."]},{"l":"Removing a Single Entity","p":["You can remove a single entity using removeOne() method. It takes a Dart entity as input parameter. It returns a FutureWriteResult object.","The entity must have a valid id field marked with @Id annotation. In case an EntityDecorator is used, the idField getter must return a valid non-null EntityId object. Otherwise, it will throw a NotIdentifiableException."]},{"l":"Removing Using a Filter","p":["You can remove multiple entities using a filter. It takes a Filter object as input parameter. It returns a FutureWriteResult object.","If the filter result matches multiple entities, then all the entities will be removed."]},{"l":"Removing Using a Filter and Options","p":["You can remove multiple entities using a filter and options. It takes a Filter object as first input parameter. It takes a boolean value as second input parameter. If the second input parameter is true, then it will remove only the first entity matched by the filter. Otherwise, it will remove all the entities matched by the filter. It returns a FutureWriteResult object."]}],[{"l":"Read Operations"},{"l":"Find Operations","p":["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."]},{"l":"Filters","p":["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."]},{"l":"Find All Entities","p":["You can find all entities in a repository by calling find(). It returns a Cursor object."]},{"l":"Finding an Entity Using Id","p":["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."]},{"l":"Finding an Entity Using a Filter","p":["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."]},{"l":"Finding an Entity Using a Filter and Options","p":["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."]},{"l":"FindOptions","p":["More information about FindOptions can be found here."]},{"l":"Cursor","p":["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."]},{"l":"Iterating over Entities","p":["The Cursor extends Stream of entities. So, you can iterate over the entities using await for loop.","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."]},{"l":"Getting the Entities","p":["You can get the entities from a Cursor using toList() method. It returns a FutureListT object."]},{"l":"Getting the First Entity","p":["You can get the first entity from a Cursor using first getter. It returns a FutureT? object."]},{"l":"Getting the Size of the Cursor","p":["You can get the size of the cursor using length getter. It returns a Futureint object."]},{"l":"Projection","p":["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:","Then you can project the lastName and address.street fields. Then you define a new entity like this:","And then you can project the cursor like this:"]},{"l":"Join","p":["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:","And you want to join these two entities using userId field. Then you can define a new entity like this:","And then you can join the cursors like this:"]},{"l":"FindPlan","p":["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."]}],[{"l":"Indexing","p":["Indexing is a way to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It is a data structure technique which is used to quickly locate and access the data in a database.","Nitrite supports indexing on a repository. It supports indexing on a single field or multiple fields. It also supports full-text indexing.","Indexes for an entity can be defined using various annotations like @Id, @Index etc. More information about annotations can be found here. It can also be managed using various methods of ObjectRepository interface."]},{"l":"Index Types","p":["Nitrite supports the following types of index out of the box:","Unique Index","Non-Unique Index","Full-text Index"]},{"l":"Unique Index","p":["A unique index ensures that the indexed field contains unique value. It does not allow duplicate value in the indexed field. It also ensures that the indexed field is not null."]},{"l":"Non-unique Index","p":["A non-unique index does not ensure that the indexed field contains unique value. It allows duplicate value in the indexed field."]},{"l":"Full-text Index","p":["A full-text index is used to search text content in an entity. It is useful when you want to search text content in an entity. It is also useful when you want to search text content in an entity in a language other than English.","Indexing on non-comparable value is not supported."]},{"l":"Custom Index","p":["You can also create your own custom index. More information about custom index can be found here."]},{"l":"Creating an Index","p":["You can define indexes for an entity using annotations. You can also create indexes using ObjectRepository interface."]},{"l":"Creating a Unique Index","p":["You can create a unique index on a single field or multiple fields. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Using Annotations","p":["You can create a unique index on a single field or multiple fields using annotations. You can use @Id annotation to create a unique index on a single field. You can use @Index annotation to create a unique index on multiple fields."]},{"l":"Using ObjectRepository","p":["You can create a unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter."]},{"l":"Creating a Non-unique Index","p":["You can create a non-unique index on a single field or multiple fields by passing the index type as IndexType.nonUnique."]},{"i":"using-annotations-1","l":"Using Annotations","p":["You can create a non-unique index on a single field or multiple fields using annotations. You can use @Index annotation to create a non-unique index on multiple fields."]},{"i":"using-objectrepository-1","l":"Using ObjectRepository","p":["You can create a non-unique index on a single field or multiple fields using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.nonUnique."]},{"l":"Creating a Full-text Index","p":["You can create a full-text index on a single field or multiple fields by passing the index type as IndexType.fullText."]},{"i":"using-annotations-2","l":"Using Annotations","p":["You can create a full-text index on a single field using annotations. You can use @Index annotation to create a full-text index on a single field."]},{"i":"using-objectrepository-2","l":"Using ObjectRepository","p":["You can create a full-text index on a single field using createIndex() method. It takes the name of the fields on which the index will be created as input parameter and the index type as IndexType.fullText.","Full-text index is not supported on multiple fields."]},{"l":"Creating Index on Iterable Field","p":["Nitrite supports creating index on iterable field. It will create index on each element of the iterable. For example, if you have an entity like this:","Then it will create index on each element of the tags list. You can also create index on tags field like this:"]},{"l":"Creating Index on Embedded Field","p":["Nitrite supports creating index on embedded field. For example, if you have entities like this:","Then it will create index on city field of Address entity. You can also create index on city field of Address entity like this:","You cannot create index on nested field if the parent field is an array."]},{"l":"Rebuilding an Index","p":["You can rebuild an index using rebuildIndex() method. It takes the name of the fields on which the index will be rebuilt as input parameter."]},{"l":"Dropping an Index","p":["You can drop an index using dropIndex() method. It takes the name of the fields on which the index will be dropped as input parameter."]},{"l":"Dropping All Indexes","p":["You can drop all indexes using dropAllIndices() method."]},{"l":"Getting All Indexes","p":["You can get all indexes using listIndices() method. It returns a FutureCollection of IndexDescriptor object."]},{"l":"IndexDescriptor","p":["IndexDescriptor is a class which contains information about an index. It contains the following information:","collectionName: The name of the collection on which the index is created.","indexType: The type of the index.","fields: A Fields object containing the name of the fields on which the index is created."]},{"l":"Checking If an Index Exists","p":["You can check if an index exists using hasIndex() method. It takes the name of the fields on which the index will be checked as input parameter."]},{"l":"Error Scenarios","p":["The following error scenarios are possible while creating an index:","If another index of any type is already created on the repository on the same field(s), then it will throw IndexingException.","If a unique index is created on a field and the field contains duplicate value, then it will throw UniqueConstraintException.","If a full-text index is created on multiple fields, then it will throw IndexingException.","If a full-text index is created on a field which is not a String, then it will throw IndexingException.","If you try to drop an index which does not exist, then it will throw IndexingException.","If you try to rebuild an index which does not exist, then it will throw IndexingException."]}],[{"l":"Other Operations"},{"l":"Size of a Repository","p":["You can get the size of a repository using size getter. It returns a future of the number of entities in the repository."]},{"l":"Clearing a Repository","p":["You can clear all the entities from a repository using clear() method. It removes all the entities from the repository and index entries from the indexes. It does not drop the repository."]},{"l":"Dropping a Repository","p":["You can drop a repository using drop() method. It removes all the entities from the repository and index entries from the indexes. It also drops all the indexes associated with the repository. It also removes the repository from the database.","You can call isDropped getter to check if the repository is dropped or not.","Any further operation on a dropped repository will throw NitriteIOException."]},{"l":"Closing a Repository","p":["You can close a repository using close() method. Any further operation on a closed repository will throw NitriteIOException.","After closing a repository, you must re-open it via Nitrite.getRepository() method to perform any operation on it.","You can call isOpen getter to check if the repository is closed or not."]},{"l":"Event Listener","p":["You can register an event listener on a repository to get notified on entity changes. The event listener is a function of type CollectionEventListener. It will receive CollectionEventInfo whenever an entity is inserted, updated or removed from the repository.","You can unsubscribe the event listener using unsubscribe() method."]},{"l":"CollectionEventInfo","p":["More on CollectionEventInfo can be found here."]},{"l":"Attributes","p":["Attributes is a metadata information associated with a repository.","You can get/set attributes on a repository. The attributes are stored in the database and can be retrieved later. The attributes are stored in a special map named $nitrite_meta_map."]},{"l":"Processors","p":["Processor can be used to process the underlying documents of a repository. More on processors can be found here."]},{"l":"Registering a Processor","p":["You can register a processor on a repository using addProcessor() method. It takes a Processor as input parameter."]},{"l":"Available Processors","p":["Nitrite provides a StringFieldEncryptionProcessor which can be used to encrypt a field before writing it into a repository and decrypt a field after reading it from a repository.","More on this is described in Support."]}],[{"l":"Filters","p":["Filters are used to specify the criteria used to select documents from a collection or repository. It provides a way to specify conditions that the documents must meet to be included in the result set. Filters are used in conjunction with the find method. The find method returns all documents in a collection that match the specified filtering criteria.","Each filtering criteria is based on a field in the document. If the field is indexed, the find operation takes advantage of the index to speed up the operation. If the field is not indexed, the find operation scans the entire collection to find matching documents."]},{"l":"Fluent API","p":["Nitrite provides a fluent API to create filters via FluentFilter class. It provides a global method where to create a filter. The where method takes a field name as input parameter and returns a FluentFilter object. The FluentFilter object provides various methods to create a filter. Here is an example:","The above code will create a filter for the field name and then filter for equality. The find method will return all documents where the field name is equal to John.","For spatial filters, use the SpatialFluentFilter class for the fluent API. Similarly it also provides a global method where to create a filter. The where method takes a field name as input parameter and returns a SpatialFluentFilter object. The SpatialFluentFilter object provides various methods to create a filter. Here is an example:","More on spatial module can be found here."]},{"l":"Usage","p":["Filters are used with the find method of NitriteCollection or ObjectRepository to retrieve documents or entities that match the filter. Here's an example:","In this example, the where and eq methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"String Extensions","p":["Nitrite provides a String extension to create filters. It creates a filter for the field name specified in the string."]},{"l":"Operator Overloading","p":["Nitrite provides operator overloading to create filters. It creates a filter for the field name specified in the string.","There are various operators available for creating filters. Here is the list:",": Greater than filter","=: Greater than or equal to filter",": Less than filter","=: Less than or equal to filter","~: Not filter",": And filter","|: Or filter","These operators are also valid on the String extension of filter. More on this is discussed in the following sections."]},{"l":"Types of Filters","p":["Nitrite filters can be grouped into the following categories:","Comparison filters","Logical filters","Array filters","Evaluation filters","Spatial filters"]},{"l":"Comparison Filters","p":["Comparison filters are used to compare a field with a value. The following comparison filters are available:","Equality (eq): Matches all documents where the value of the field equals the specified value.","Inequality (notEq): Matches all documents where the value of the field is not equal to the specified value.","Greater than (gt): Matches all documents where the value of the field is greater than the specified value.","Greater than or equal to (gte): Matches all documents where the value of the field is greater than or equal to the specified value.","Less than (lt): Matches all documents where the value of the field is less than the specified value.","Less than or equal to (lte): Matches all documents where the value of the field is less than or equal to the specified value.","Within (within): Matches all documents where the value of the field equals any value in the specified array.","Not in (notIn): Matches all documents where the value of the field does not equal any value in the specified array.","Between (between): Matches all documents where the value of the field is between the specified values.","All (all): Matches all documents in the collection."]},{"l":"Equality Filter","p":["The equality filter is used to match documents where the value of a field equals the specified value. The following example shows how to use the equality filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Inequality Filter","p":["The inequality filter is used to match documents where the value of a field is not equal to the specified value. The following example shows how to use the inequality filter:","In this example, the where() and notEq() methods are used to create an inequality filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than Filter","p":["The greater than filter is used to match documents where the value of a field is greater than the specified value. The following example shows how to use the greater than filter:","In this example, the where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Greater Than or Equal To Filter","p":["The greater than or equal to filter is used to match documents where the value of a field is greater than or equal to the specified value. The following example shows how to use the greater than or equal to filter:","In this example, the where() and gte() methods are used to create a greater than or equal to filter that matches documents where the age field is greater than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than Filter","p":["The less than filter is used to match documents where the value of a field is less than the specified value. The following example shows how to use the less than filter:","In this example, the where() and lt() methods are used to create a less than filter that matches documents where the age field is less than 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Less Than or Equal To Filter","p":["The less than or equal to filter is used to match documents where the value of a field is less than or equal to the specified value. The following example shows how to use the less than or equal to filter:","In this example, the where() and lte() methods are used to create a less than or equal to filter that matches documents where the age field is less than or equal to 18. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Within Filter","p":["The within filter is used to match documents where the value of a field equals any value in the specified array. The following example shows how to use the in filter:","In this example, the where() and within() methods are used to create an in filter that matches documents where the name field equals \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not In Filter","p":["The not in filter is used to match documents where the value of a field does not equal any value in the specified array. The following example shows how to use the not in filter:","In this example, the where() and notIn() methods are used to create a not in filter that matches documents where the name field does not equal \"John\" or \"Jane\". The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Between Filter","p":["The between filter is used to match documents where the value of a field is between the specified values. The following example shows how to use the between filter:","In this example, the where() and between() methods are used to create a between filter that matches documents where the age field is between 18 and 30. The filter is then passed to the find method to retrieve the matching documents.","There two other optional parameters available in the between method. The first parameter is lowerInclusive which is a boolean value to indicate whether the lower bound is inclusive or not. The default value is true. The second parameter is upperInclusive which is a boolean value to indicate whether the upper bound is inclusive or not. The default value is true."]},{"l":"All Filter","p":["The all filter is used to match all documents in the collection. The following example shows how to use the all filter:","In this example, the all constant is used to create an all filter that matches all documents in the collection. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Logical Filters","p":["Logical filters are used to combine multiple filters into a single filter. The following logical filters are supported:","And (and): Matches all documents that satisfy all the specified filters.","Or (or): Matches all documents that satisfy at least one of the specified filters.","Not (not): Matches all documents that do not satisfy the specified filter."]},{"l":"And Filter","p":["The and filter is used to match documents that satisfy all the specified filters. The following example shows how to use the and filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the and() method to create an and filter that matches documents where the name field equals \"John\" and the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The and() method can be used to combine any number of filters. The following example shows how to combine three filters:","Operators can also be used to combine filters. The following example shows how to combine three filters using operators:","The global and() method can also be used to combine filters. The following example shows how to combine three filters using the global and() method:","In this example, the and() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Or Filter","p":["The or filter is used to match documents that satisfy at least one of the specified filters. The following example shows how to use the or filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The where() and gt() methods are used to create a greater than filter that matches documents where the age field is greater than 18. The two filters are then combined using the or() method to create an or filter that matches documents where the name field equals \"John\" or the age field is greater than 18. The filter is then passed to the find method to retrieve the matching documents.","The or() method can be used to combine any number of filters. The following example shows how to combine three filters:","Operators can also be used to combine filters. The following example shows how to combine three filters using operators:","The global or() method can also be used to combine filters. The following example shows how to combine three filters using the global or() method:","In this example, the or() method is used to combine three filters into a single filter. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Not Filter","p":["The not filter is used to match documents that do not satisfy the specified filter. The following example shows how to use the not filter:","In this example, the where() and eq() methods are used to create an equality filter that matches documents where the name field equals \"John\". The not() method is then used to create a not filter that matches documents where the name field does not equal \"John\". The filter is then passed to the find method to retrieve the matching documents.","The not() method can be used to negate any filter. The following example shows how to negate a greater than filter:"]},{"l":"Array Filters","p":["Array filters are used to match documents based on the values in an array field. The following array filters are supported:","Element match (elemMatch): Matches all documents where the array field contains at least one element that matches the specified filter."]},{"l":"Element Match Filter","p":["The element match filter is used to match documents where the array field contains at least one element that matches the specified filter. The following example shows how to use the element match filter:","Let's say we have a collection that contains documents with the following structure:","The following example shows how to use the element match filter to find all documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\":","In this example, the where() and elemMatch() methods are used to create an element match filter that matches documents where the addresses field contains at least one element that matches the filter where the city field equals \"New York\". The filter is then passed to the find method to retrieve the matching documents.","The elemMatch filter can be used to search an array of elements for a specific value. The following example shows how to use the elemMatch filter to find all documents where the data field contains at least one element that is greater than 2 or less than equal to 5:","The global $ variable is used to create a filter for the current element in the array. The $.gt(2).or($.lte(5)) filter is used to match documents where the data field contains at least one element that is greater than 2 or less than equal to 5. The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Evaluation Filters","p":["Evaluation filters are used to match documents based on evaluating the value of any field in a document. The following evaluation filters are supported:","Text (text): Matches all documents which contain a specified full-text search expression.","Regex (regex): Matches all documents where values contain a specified regular expression."]},{"l":"Text Filter","p":["The text filter is used to match documents which contain a specified full-text search expression. The following example shows how to use the text filter:","In this example, the where() and text() methods are used to create a text filter that matches documents where the name field contains the word \"John\". The filter is then passed to the find method to retrieve the matching documents.","The text filter supports glob patterns. The following example shows how to use the text filter with glob patterns:","The text filter can only be used with a field that has a full-text index."]},{"l":"Regex Filter","p":["The regex filter is used to match documents where values contain a specified regular expression. The following example shows how to use the regex filter:","In this example, the where() and regex() methods are used to create a regex filter that matches documents where the name field matches the regular expression \"John.*\". The filter is then passed to the find method to retrieve the matching documents.","This filter scans the entire collection to find matching documents. It cannot take advantage of an index."]},{"l":"Spatial Filters","p":["Spatial filters are used to match documents based on the values in a spatial field. The following spatial filters are supported:","Near (near): Matches all documents where the spatial field is within the specified distance from the specified point.","Within (within): Matches all documents where the spatial field is within the specified shape.","Intersects (intersects): Matches all documents where the spatial field intersects the specified shape.","To use spatial filters, you need create a spatial index on the field, which needs the nitrite-spatial module to be loaded. More on this can be found here.","Spatial filters can only be used with a field that has a spatial index."]},{"l":"Near Filter","p":["The near filter is used to match documents where the value of the spatial field is near the specified point. The following example shows how to use the near filter:","In this example, the where() and near() methods are used to create a near filter that matches documents where the location field is within 1000 meters of the point (40.730610, -73.935242). The filter is then passed to the find method to retrieve the matching documents."]},{"i":"within-filter-1","l":"Within Filter","p":["The within filter is used to match documents where the value of the spatial field is within the specified shape. The following example shows how to use the within filter:","In this example, the where() and within() methods are used to create a within filter that matches documents where the location field is within the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]},{"l":"Intersects Filter","p":["The intersects filter is used to match documents where the value of the spatial field intersects the specified shape. The following example shows how to use the intersects filter:","In this example, the where() and intersects() methods are used to create an intersects filter that matches documents where the location field intersects the polygon ((0 0, 0 3, 3 3, 3 0, 0 0)). The filter is then passed to the find method to retrieve the matching documents."]}],[{"l":"Transaction","p":["A transaction is a single logical unit of work which accesses and possibly modifies the contents of a database. Transactions access data using read and write operations.","Nitrite supports transactional operations on its collections and repositories. A transaction can be committed or rolled back. Once a transaction is committed, all the changes are persisted to the disk. If a transaction is rolled back, all the changes are discarded."]},{"l":"Transaction on NitriteCollection","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a NitriteCollection, the Transaction.getCollection() method can be used. All the operations performed on the collection will be part of the transaction.","Nitrite also provides a Session.executeTransaction() method to execute a transactional operation. The Session.executeTransaction() method takes a callback function as an argument. The callback function will be executed inside a transaction.","If any exception occurs inside the transaction, the transaction will be rolled back. If you want to rollback a transaction only for certain exceptions, you can use the Session.executeTransaction() method with rollbackFor parameter. The rollbackFor parameter takes a list of exception types for which the transaction will be rolled back. For any other exceptions, the transaction will be committed.","Any find operations performed inside a transaction will return all the documents including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed documents."]},{"l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","NitriteCollection.createIndex()","NitriteCollection.rebuildIndex()","NitriteCollection.dropIndex()","NitriteCollection.dropAllIndices()","NitriteCollection.drop()","NitriteCollection.clear()","NitriteCollection.close()"]},{"l":"Transaction on ObjectRepository","p":["A transaction can be started from a session using the Session.beginTransaction() method. To start a transactional operation on a ObjectRepository, the Transaction.getRepository() method can be used. All the operations performed on the repository will be part of the transaction.","Nitrite also provides a Session.executeTransaction() method to execute a transactional operation. The Session.executeTransaction() method takes a callback function as an argument. The callback function will be executed inside a transaction.","If any exception occurs inside the transaction, the transaction will be rolled back. If you want to rollback a transaction only for certain exceptions, you can use the Session.executeTransaction() method with rollbackFor parameter. The rollbackFor parameter takes a list of exception types for which the transaction will be rolled back. For any other exceptions, the transaction will be committed.","Any find operations performed inside a transaction will return all the entities including the uncommitted ones.","Any find operations performed outside a transaction will return only the committed entities."]},{"i":"auto-commit-operations-1","l":"Auto-commit Operations","p":["Certain operations are auto-committed in Nitrite. Those operations are not part of a transaction and cannot be rolled back. The following operations are auto-committed:","ObjectRepository.createIndex()","ObjectRepository.rebuildIndex()","ObjectRepository.dropIndex()","ObjectRepository.dropAllIndices()","ObjectRepository.drop()","ObjectRepository.clear()","ObjectRepository.close()"]},{"l":"Session","p":["A session represents a transactional context for a Nitrite database. Session is used to create a new transaction. A session should be closed after use to release any resources held by it. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Create a Session","p":["A session can be created using the Nitrite.createSession() method. Multiple sessions can be created for a Nitrite database."]},{"l":"Close a Session","p":["A session can be closed using the Session.close() method. If a session is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Checking If Session is Active","p":["A session can be checked if it is active or not using the Session.isActive getter."]},{"l":"Managing Transactions","p":["A transaction can be started using the Session.beginTransaction() method.","A transaction can be committed using the Transaction.commit() method. If a transaction is committed, all the changes are persisted to the disk.","A transaction can be rolled back using the Transaction.rollback() method. If a transaction is rolled back, all the changes are discarded.","A transaction can be closed using the Transaction.close() method. If a transaction is closed and the transaction is not committed, all opened transactions will be rolled back."]},{"l":"Querying Transaction State","p":["The current state of a transaction can be retrieved using the Transaction.getState() method. It returns an enum of type TransactionState.","Possible values for TransactionState are:","TransactionState.active- The transaction is active.","TransactionState.committed- The transaction is committed.","TransactionState.partiallyCommitted- The transaction is partially committed.","TransactionState.closed- The transaction is closed.","TransactionState.failed- The transaction is failed.","TransactionState.aborted- The transaction is aborted."]}],[{"l":"Schema Migration","p":["A migration is a set of changes to the schema that can be applied to a database. Migrations are used to keep the database schema up to date with the codebase. It contains a queue of instructions that are executed in order to update the database schema from one version to the next.","The migration is executed only once for a specific schema version.ni If you want to execute the migration again, you need to change the schema version of the database.","For example, if you have a database with the schema version 1 and you want to update it to version 2, you need to apply the migration steps from version 1 and version 2.","The migration instructions are executed in the order they are added to the migration. The order of the instructions is important. For example, if you want to rename a field, you need to add the renameField instruction before the deleteField instruction. Otherwise, the deleteField instruction will fail.","Once a migration is applied to a database, it cannot be reverted. If you want to revert a migration, you need to create a new migration that will revert the changes.","Nitrite provides a set of instructions that can be used to update the database schema. These instructions can be grouped into three categories:","Database Instruction","Collection Instruction","Repository Instruction"]},{"l":"Database Instruction","p":["Database instructions are used to perform operations on the database. The following instructions are available:"]},{"l":"Add User","p":["Adds an instruction to set a user authentication to the database. The user will be used to open the database.","Nitrite database supports only one user authentication per database. If you try to add a new user when there is already a user authentication present, the migration will fail throwing a NitriteSecurityException."]},{"l":"Change Password","p":["Adds an instruction to change the password for the user authentication to the database.","The user authentication must be present in the database. If you try to change the password for a user that does not exist, the migration will fail throwing a NitriteSecurityException.","If you try to change the password for a user with a wrong password, the migration will also fail throwing a NitriteSecurityException."]},{"l":"Drop Collection","p":["Adds an instruction to drop a NitriteCollection from the database."]},{"l":"Drop Repository","p":["Adds an instruction to drop a ObjectRepository from the database. There are several ways to drop a repository:"]},{"l":"Drop by Type"},{"l":"Drop by Type and Key Name"},{"l":"Drop by EntityDecorator"},{"l":"Drop by EntityDecorator and Key Name"},{"l":"Drop by Entity Name"},{"l":"Drop by Entity Name and Key Name"},{"l":"Custom Instruction","p":["Adds a custom instruction to the migration. The custom instruction is a callback function that takes a Nitrite instance as an argument. The callback function can be used to perform any operation on the database."]},{"l":"Collection Instruction","p":["Collection instructions are used to perform operations on a NitriteCollection. The following instructions are available:"]},{"l":"Rename Collection","p":["Adds an instruction to rename a NitriteCollection."]},{"l":"Add Field","p":["Adds an instruction to add new field to the documents of a NitriteCollection."]},{"l":"Add Field with Null Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be null."]},{"l":"Add Field with Default Value","p":["The new field will be added to all the documents of the collection. The value of the new field will be new-value."]},{"l":"Add Field with Generator","p":["The new field will be added to all the documents of the collection. The value of the new field will be the value returned by the Generator."]},{"l":"Generator","p":["A Generator is a function that takes a Document as input and returns a value. The value returned by the Generator will be used as the value of the new field."]},{"l":"Rename Field","p":["Adds an instruction to rename a field of the documents of a NitriteCollection."]},{"l":"Delete Field","p":["Adds an instruction to delete a field from the documents of a NitriteCollection."]},{"l":"Drop Index","p":["Adds an instruction to drop an index from a NitriteCollection.","The drop index instruction can be used to drop a single field index or a compound index."]},{"l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a NitriteCollection."]},{"l":"Create Index","p":["Adds an instruction to create an index on a NitriteCollection.","The create index instruction can be used to create a single field index or a compound index."]},{"l":"Repository Instruction","p":["Repository instructions are used to perform operations on a ObjectRepository. The following instructions are available:"]},{"l":"Rename Repository","p":["Adds an instruction to rename a ObjectRepository."]},{"i":"add-field-1","l":"Add Field","p":["Adds an instruction to add new field to the entity of a ObjectRepository."]},{"i":"add-field-with-null-value-1","l":"Add Field with Null Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be null."]},{"i":"add-field-with-default-value-1","l":"Add Field with Default Value","p":["The new field will be added to all the entities of the repository. The value of the new field will be new-value."]},{"l":"Add Field with Generator Function","p":["The new field will be added to all the entities of the repository. The value of the new field will be the value returned by the Generator function.","More information about the Generator can be found here."]},{"i":"rename-field-1","l":"Rename Field","p":["Adds an instruction to rename a field of the entity of a ObjectRepository."]},{"i":"delete-field-1","l":"Delete Field","p":["Adds an instruction to delete a field from the entity of a ObjectRepository."]},{"l":"Change Data Type","p":["Adds an instruction to change the data type of a field of the entity of a ObjectRepository."]},{"l":"Type Converter","p":["A TypeConverter is a function that takes a value of one type as input and returns a value of another type. The value returned by the TypeConverter will be used as the value of the new field."]},{"l":"Change Id Field","p":["Adds an instruction to change the id field of the entity of a ObjectRepository."]},{"i":"drop-index-1","l":"Drop Index","p":["Adds an instruction to drop an index from a ObjectRepository.","The drop index instruction can be used to drop a single field index or a compound index."]},{"i":"drop-all-indexes-1","l":"Drop All Indexes","p":["Adds an instruction to drop all the indexes from a ObjectRepository."]},{"i":"create-index-1","l":"Create Index","p":["Adds an instruction to create an index on a ObjectRepository.","The create index instruction can be used to create a single field index or a compound index."]}],[{"l":"Module System","p":["Nitrite is a modular database engine. The core functionality of Nitrite is provided by the nitrite module. The nitrite module is the only mandatory module for Nitrite. All other modules are optional and can be added to the project as per the requirement.","Nitrite's module system is built on top of NitritePlugin and NitriteModule interfaces. A module is a collection of plugins. While opening a database, all the modules must be loaded. Each module then load and initialize all the plugins it contains.","The nitrite module provides default implementation of all the interfaces. For example, the nitrite module provides in-memory storage implementation. If you want to use on-disk storage, you need to add a storage module to your project.","The main advantage of Nitrite's module system is that it allows you to extend the functionality of Nitrite without adding all the dependencies at once in your project. You only need to add dependencies that you want to use. This helps to keep the application size small.","You can write your own module and plugin and add it to the project. The module system also allows you to replace the default implementation of any plugin. For example, if you want to use a different storage engine, you can write your own storage module and add it to the project."]},{"l":"NitriteModule","p":["The NitriteModule interface is the base interface for all the modules. It encapsulates a set of plugins. A module must be loaded before opening a database.","To create a module, you need to implement the NitriteModule interface. The NitriteModule interface has a single getter plugins which returns a set of plugins."]},{"l":"Dynamic Module","p":["A dynamic module can be created using the global module() method. A dynamic module is a module which is not loaded from any package, instead it is created dynamically.","A dynamic module is useful when you want to create a module from a set of plugins at runtime."]},{"l":"Available Modules","p":["The following modules are available from Nitrite.","Storage Module","Spatial Module"]},{"l":"NitritePlugin","p":["The NitritePlugin interface is the base interface for all the plugins. A plugin is a single unit of functionality. A plugin must be loaded via a NitriteModule before opening a database."]},{"l":"Initializing Plugin","p":["A plugin can be initialized by implementing the initialize() method of the NitritePlugin interface. The initialize() method is called by the module when the plugin is loaded."]},{"l":"Closing Plugin","p":["A plugin can be closed by implementing the close() method of the NitritePlugin interface. The close() method is called by the module when the database is closed."]},{"l":"Available Plugins","p":["Following are the available plugins in Nitrite which can be used to extend the functionality of Nitrite:","NitriteStore- A plugin to provide storage functionality.","NitriteMapper- A plugin to provide object mapping functionality.","NitriteIndexer- A plugin to provide indexing functionality.","EntityConverter- A plugin to provide entity conversion functionality.","You can implement any of the above plugins to extend the functionality of Nitrite."]},{"l":"NitriteStore","p":["The NitriteStore interface is the base interface for all the storage plugins. A storage plugin is responsible for storing and retrieving data from the underlying storage. The NitriteStore interface extends the NitritePlugin interface.","A reference implementation of the NitriteStore interface can be found here."]},{"l":"NitriteMapper","p":["The NitriteMapper interface is the base interface for all the object mapping plugins. A mapper plugin is responsible for mapping an object to a document and vice-versa. The NitriteMapper interface extends the NitritePlugin interface."]},{"l":"NitriteIndexer","p":["The NitriteIndexer interface is the base interface for all the indexing plugins. An indexer plugin is responsible for indexing a document. The NitriteIndexer interface extends the NitritePlugin interface.","While creating a new index, Nitrite uses the indexType getter to determine the type of the index. The indexType getter must return a unique string for each type of index. So when you create a new index, you need to pass the same string to the IndexOptions.indexType."]},{"l":"EntityConverter","p":["An EntityConverter is a plugin which is responsible for converting an object to a document and vice-versa. The EntityConverter interface extends the NitritePlugin interface.","If Nitrite is using the default SimpleNitriteMapper, then all EntityConverter s from all the loaded modules are automatically registered with the mapper. If you are using a custom mapper, then you need to register the EntityConverter with the mapper manually.","One of the available EntityConverter in Nitrite is GeometryConverter from the spatial module. It is responsible for converting a Geometry object of JTS to a document and vice-versa. Once you load the spatial module, the GeometryConverter is automatically registered with the mapper. You can find more information about GeometryConverter here.","If you want to load multiple EntityConverter s, while opening the database, you can also create a dynamic module and load it instead of using the NitriteBuilder.registerEntityConverter() method multiple times."]}],[{"l":"Storage Module","p":["Nitrite provides a default storage module which is in-memory. It means all the data is stored in memory and is volatile. Once the application is closed, all the data is lost. If you want to persist the data, you want to use on-disk storage, you need to add a storage module to your project. There are choices of storage modules available for Nitrite. You can choose from below as per your requirement.","Hive Module","You can also write your own storage module and add it to the project. More details about writing your own storage module is available here."]}],[{"l":"Hive Modules","p":["Nitrite provides a persistent storage module based on Hive. Hive is a lightweight and blazing fast, file based key-value store written in pure Dart."]},{"l":"Adding Hive Module","p":["To use Hive module, you need add below dependency to your project:"]},{"l":"Using Hive Module","p":["To use Hive as your persistent storage, you need to load the HiveModule while opening the database. You can also configure the module as per your requirement.","Once the module is loaded, you can use the database as usual. All the data will be persisted in the file you specified."]},{"l":"Configuring Hive Module","p":["You can configure the Hive module as per your requirement. The following configuration options are available:","path- the file path where the database will be stored. It is a directory path.","backendPreference- the preference for the backend to use. It takes an enum HiveStorageBackendPreference.","encryptionCipher- the encryption cipher used to encrypt the database. If not specified, the database will not be encrypted. It takes a HiveCipher instance.","compactionStrategy- the compaction strategy to use. It takes a function of type CompactionStrategy.","crashRecovery- if set to true, the database will be recovered from crash. The default value is false.","addTypeAdapter()- you can add your own type adapter to the Hive database. It takes a TypeAdapter instance.","addStoreEventListener()- you can add your own store event listener to the Hive database. It takes a StoreEventListener function as argument.","Nitrite provides a builder pattern to configure the module. You can use the HiveModule.withConfig() method to get the builder instance. The builder has a build() method which returns the module instance.","For more details about Hive configuration, please visit Hive Documentation."]}],[{"l":"Custom Storage Modules","p":["The beauty of Nitrite is that it is highly extensible. You can write your own storage module and use it with Nitrite. Nitrite provides a simple interface StoreModule to write your own storage module."]},{"l":"StoreModule Interface","p":["To write a custom storage module, you need to implement the StoreModule interface. The interface has only one method getStore() which returns an implementation of NitriteStore interface.","Optionally, you can also implement the StoreConfig interface to provide configuration options for your storage module."]},{"l":"NitriteStore Interface","p":["The NitriteStore is the storage abstraction layer for Nitrite. It provides the basic operations required by Nitrite to store and retrieve data. A NitriteStore is responsible for managing NitriteMap and NitriteRTree instances which are the main building blocks of database collections."]},{"l":"StoreConfig Interface","p":["The StoreConfig interface provides configuration options for your storage module. You can use this interface to provide configuration options for your storage module."]},{"l":"NitriteMap Interface","p":["The NitriteMap interface is the abstraction layer for Nitrite's key-value store. It provides the basic operations required by a collection to store and retrieve data. A NitriteMap is responsible for managing NitriteId and Document instances which are the main unit of data storage in Nitrite."]},{"l":"NitriteRTree Interface","p":["The NitriteRTree interface is the abstraction layer for Nitrite's R-Tree. It provides the basic operations required by a spatial index to store and retrieve data."]},{"l":"Example","p":["Let's write a simple storage module which stores data in a Map object. The module will be a simple in-memory storage module. The module will be configured with a Map object and will use it to store data."]},{"l":"Store Module","p":["The following code snippet shows the implementation of the storage module."]},{"l":"Store Config","p":["The following code snippet shows the implementation of the store configuration.","And the builder class for the configuration."]},{"l":"Nitrite Store","p":["The following code snippet shows the implementation of the NitriteStore interface."]},{"l":"Nitrite Map","p":["The following code snippet shows the implementation of the NitriteMap interface."]},{"l":"Nitrite RTree","p":["The following code snippet shows the implementation of the NitriteRTree interface."]}],[{"l":"Spatial Module","p":["Nitrite Spatial module provides support for spatial queries. The module uses JTS port of the dart package dart_jts for spatial operations."]},{"l":"Adding Spatial Module","p":["To use Spatial module to your project, you need to add below dependency to your project:"]},{"l":"Using Spatial Module","p":["To use Spatial module, you need to load the SpatialModule while opening the database.","If you are using nitrite_hive_adapter as your storage module, you need to register the GeometryAdapter with the Hive database.","If Nitrite is using the default SimpleNitriteMapper, then the SpatialModule will automatically register the GeometryConverter with the mapper. If you are using your own custom mapper, then you need to register the GeometryConverter with the mapper."]},{"l":"GeometryConverter","p":["GeometryConverter is an EntityConverter which is used to convert Geometry object of Dart JTS to Document and vice-versa. It is used to store the Geometry object in the database."]},{"l":"Spatial Index","p":["Spatial module uses R-Tree index to store the spatial data.","To create a spatial index, you need to pass the index type as spatialIndex while creating the index. spatialIndex is a global constant defined in nitrite_spatial package.","Spatial index is not supported on multiple fields."]},{"l":"Spatial Filter","p":["Spatial module supports several filters to query spatial data. To know more about filters, please refer to Spatial Filters."]}],[{"l":"Usage","p":["Nitrite provides some additional functionalities via nitrite-support library. You can use the library to enable encryption, import/export database etc."]},{"l":"Adding nitrite-support","p":["To use nitrite-support to your project, add the following dependency to your project:"]}],[{"i":"importexport","l":"Import/Export","p":["Nitrite provides import/export functionality via nitrite-support library. You can import/export your database to/from a file in JSON format. You can choose to import/export the entire database or a specific collection."]},{"l":"Exporting Database","p":["To export the entire database in JSON format, you can use the Exporter class of nitrite-support library. You can use the Exporter.withOptions() method to construct an instance of Exporter.","The database must be in closed state before exporting."]},{"l":"Export Options","p":["collections- the list of collections to export. The rules for specifying the collection names are as follows:","dbFactory- the NitriteFactory function to use for export. It is used to create the Nitrite instance for export. It's a mandatory field.","exportData- whether to export data or not. It's an optional field, if not provided, it will be set to true.","exportIndices- whether to export indices or not. It's an optional field, if not provided, it will be set to true.","If a non-empty list is specified, only the collections in the list will be exported.","If a non-empty list is specified, only the repositories in the list will be exported.","If a non-empty map is specified, only the keyed repositories in the map will be exported.","If an empty list is specified, no collection will be exported.","If an empty list is specified, no repository will be exported.","If an empty map is specified, no keyed repository will be exported.","If null is specified, all collections will be exported.","If null is specified, all keyed repositories will be exported.","If null is specified, all repositories will be exported.","keyedRepositories- the map of keyed repositories to export. The rules for specifying the keyed repository names are as follows:","repositories- the list of repositories to export. The rules for specifying the repository names are as follows:","The Exporter.withOptions() method provides various options to configure the export process. You can set the following options:"]},{"l":"Example","p":["First create a method to create a Nitrite instance, which will be used as the nitriteFactory.","Then create the Exporter instance and export the database.","The source.json file will contain the exported data in JSON format."]},{"l":"Importing Database","p":["To import the entire database from an exported JSON data, you can use the Importer class of nitrite-support library. You can use the Importer.withOptions() method to construct an instance of Importer.","The database must be in closed state before importing."]},{"l":"Import Options","p":["The Importer.withOptions() method provides various options to configure the import process. You can set the following options:","dbFactory- the NitriteFactory function to use for import. It is used to create the Nitrite instance for import. It's a mandatory field."]},{"i":"example-1","l":"Example","p":["First create the Importer instance and configure it.","The nitrite_dest.db file will contain the imported data. You can open the database and use it."]}],[{"l":"Encryption","p":["Nitrite provides field level encryption support via nitrite-support module. You can encrypt your data using with or without a password."]},{"l":"Field Level Encryption","p":["Nitrite provides a StringFieldEncryptionProcessor utility class to encrypt and decrypt a field of a document. It is a Processor implementation. It uses AES to encrypt and decrypt data.","While initializing the StringFieldEncryptionProcessor, you can either provide a password or not. If you provide a password, the processor will use the password to encrypt and decrypt data. If you do not provide a password, the processor will use a random key to encrypt and decrypt data."]}],[{"l":"Java Examples","p":["Here we discuss about an Android todo application using Nitrite database. It uses nitrite as a file based storage engine. It demonstrates the use of Nitrite database in an Android application. The full source code is available here. This tutorial assumes that you have basic knowledge of Android development."]},{"l":"Setup","p":["To use Nitrite in your Android application, you need to add the following dependency in your app's build.gradle file.","Also add these pro-guard rules in your proguard-rules.pro file."]},{"l":"Entity Classes","p":["Define a simple Todo entity class to hold your todo data:","And, a list of TodoItem can be represented as:"]},{"l":"Database Initialization","p":["To initialize the database and to maintain a singleton instance of the database, you need to create a singleton class NitriteManager as follows:","Next create a data access layer DataBaseManager for CRUD operations:"]},{"l":"Activity","p":["Now you need to create two activities, one for the todo list and another for the menu."]},{"l":"Todo List Activity"},{"l":"Menu Activity","p":["The other resources are available in the source code."]}],[{"l":"Flutter Examples","p":["Here we discuss about a flutter todo application using Nitrite database. It uses nitrite as a file based storage engine. It also uses Riverpod for state management. It demonstrates the use of Nitrite database in a flutter application. The full source code is available here. This tutorial assumes that you have basic knowledge of flutter and riverpod."]},{"l":"Setup","p":["Add the following Nitrite dependencies in your pubspec.yaml file along with path_provider and riverpod_generator:"]},{"l":"Entity Classes","p":["Define a simple Todo entity class to hold your todo data:","And run the following command to generate the _$TodoEntityMixin:","This command will generate the models.no2.dart file in the same directory."]},{"l":"Database Initialization","p":["Next create a Nitrite database provider using riverpod:","Now using the dbProvider, create a todo ObjectRepository provider:","And other required providers for listing and searching:","Now again run the following command to generate the providers:"]},{"l":"UI","p":["Now define a todo widget to display a single time and define different actions on it:","And a todo list widget to display the list of todos:","Now you can use these widgets in your app and other widgets to add new todo, search, etc."]}],[{"l":"Showcase"},{"l":"Showcase Your Application","p":["If you are using Nitrite Database in your application, please fill up the form below. We will showcase your application in this page."]}],[{"l":"Frequently Asked Questions"},{"i":"what-is-nitrite","l":"What is Nitrite?","p":["Nitrite is a server-less embedded database ideal for desktop, mobile or small web applications. It's an open source, self-contained database. It supports both in-memory and file based persistent store."]},{"i":"is-nitrite-an-rdbms","l":"Is Nitrite an RDBMS?","p":["No, Nitrite is not an RDBMS. It's a NoSQL database. It's a document store with support for indexing, full-text search, event listeners, embedded and in-memory modes, encryption, and many other features."]},{"i":"what-is-the-difference-between-nitrite-and-sqlite","l":"What is the difference between Nitrite and SQLite?","p":["Nitrite is a NoSQL document store, whereas SQLite is an RDBMS. Nitrite is a document store, whereas SQLite is a relational store. Nitrite has pure Java, Dart implementations, whereas SQLite has C/C++ implementation and native bindings are needed for other languages."]},{"i":"which-platforms-are-supported-by-nitrite","l":"Which platforms are supported by Nitrite?","p":["Nitrite Java is supported on all platforms where Java is supported. Nitrite Flutter is supported on all platforms where Dart is supported."]},{"i":"when-should-i-use-nitrite","l":"When should I use Nitrite?","p":["Nitrite is a good choice for desktop, mobile or small web applications. It's a good choice for applications where you don't want to install a separate database server. It's a good choice for applications where you want to store data in-memory."]},{"i":"what-is-the-performance-of-nitrite","l":"What is the performance of Nitrite?","p":["Nitrite is highly performant, though it heavily depends on the underlying storage backend implementation. A JMH benchmark of Nitrite for Java is available here where you can find its performance amongst various storage backends against SQLite."]},{"i":"does-nitrite-support-replication-over-network","l":"Does Nitrite support replication over network?","p":["No, Nitrite doesn't support replication over network. It's a server-less embedded database. If you are looking for replication, you can subscribe to collection events using CollectionEventListener and replicate the data over network."]},{"i":"what-happened-to-nitrite-datagate-server","l":"What happened to Nitrite DataGate Server?","p":["Nitrite DataGate Server is now deprecated. It's no longer maintained due to lack of interest from the community. If you are looking for it to be revived, please vote here. If enough people are interested, it will be revived."]},{"i":"what-happened-to-nitrite-explorer","l":"What happened to Nitrite Explorer?","p":["Nitrite Explorer is now deprecated. It's no longer maintained due to lack of interest from the community. If you are looking for it to be revived, please vote here. If enough people are interested, it will be revived."]},{"i":"what-if-i-find-any-issues-in-the-documentation","l":"What if I find any issues in the documentation?","p":["If you find any issues in the documentation, please raise an issue here."]},{"i":"what-if-i-had-any-suggestionsquestions","l":"What if I had any suggestions/questions?","p":["If you have any suggestions or questions about Nitrite, please start a discussion here."]},{"i":"what-is-the-license-of-nitrite","l":"What is the license of Nitrite?","p":["Nitrite is licensed under Apache License 2.0. It's free to use in both commercial and non-commercial applications. If you are using Nitrite in your commercial application, please consider donating to the project."]},{"i":"how-can-i-donate-to-nitrite","l":"How can I donate to Nitrite?","p":["If you like Nitrite and want to support the project, please consider donating to the project. You can donate via GitHub Sponsors."]}]];
\ No newline at end of file
diff --git a/showcase/index.html b/showcase/index.html
index 163d532..a7e28b5 100644
--- a/showcase/index.html
+++ b/showcase/index.html
@@ -3,7 +3,7 @@
-
+
@@ -31,12 +31,12 @@
-
+
-
+
-
-
+
+
diff --git a/sitemap.xml.gz b/sitemap.xml.gz
index fad1e0b..20875c3 100644
Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ