Skip to content

Latest commit

 

History

History
216 lines (161 loc) · 7.98 KB

File metadata and controls

216 lines (161 loc) · 7.98 KB

Couchbase Lite — Core Concepts

Platform-agnostic reference shared by mobile-android and mobile-ios.


What is Couchbase Lite

Couchbase Lite is an embedded JSON document database that runs entirely on-device. It works fully offline and syncs to Couchbase Server via Sync Gateway or Capella App Services when connectivity is available.

Key properties:

  • Embedded — no separate server process; the database is a file on the device
  • JSON documents — schema-free; each document is a key-value map
  • Collections — logical groupings of documents within a scope (analogous to tables)
  • Offline-first — reads and writes work without a network connection
  • Sync — bidirectional replication with conflict resolution handled automatically

Database and Collection Hierarchy

Database
└── Scope (default: _default)
    └── Collection (default: _default)
        └── Document (JSON key-value map)
  • A database maps to a .cblite2 file on disk.
  • A scope groups related collections (e.g. commerce, analytics).
  • A collection is the unit of query and replication. Use named collections to separate document types instead of using a type field.
  • The default collection (_default._default) is always present and is what _ refers to in SQL++ string queries.

Document Model

Each document has:

  • A document ID — string key, auto-generated UUID if not specified
  • A sequence number — monotonically increasing, used for change tracking
  • A revision ID — used internally for conflict detection
  • A body — arbitrary JSON key-value map (no fixed schema)

Always retrieve before updating. Couchbase Lite uses optimistic concurrency. Saving a MutableDocument derived from a stale read will be rejected if the document was modified concurrently. Always call getDocument / document(id:) immediately before mutating.


CRUD Semantics

Operation Notes
Create Use auto-generated ID unless you have a natural key
Read Returns null/nil if not found — always check
Update Retrieve → mutate → save; never construct a MutableDocument from scratch for an existing doc
Delete Leaves a tombstone; document is purged from sync after the tombstone replicates
Purge Removes immediately with no tombstone; use only for local-only cleanup

Live Queries

A live query re-executes automatically whenever the underlying data changes. The change listener receives a QueryChange object containing the new result set (or an error).

  • Register a listener with addChangeListener — returns a ListenerToken
  • Always call token.remove() when the listener is no longer needed (e.g. in onStop / deinit) to prevent memory leaks
  • The listener fires on a background thread; dispatch UI updates to the main thread

Indexes

Type Use case
Value index Speed up WHERE and ORDER BY on specific properties
Full-text index Enable MATCH queries for full-text search
Vector index (EE) Enable approximate nearest-neighbour search

Create indexes before running queries that need them. Index creation is synchronous and blocks until complete.


Full-Text Search

Full-text search requires a full-text index on the target property. Use FullTextFunction.match() in QueryBuilder or MATCH() in SQL++ string queries. Supports stemming, stop words, and ranking by relevance.


Blobs

Blobs store binary data (images, audio, PDFs) attached to a document:

  • Stored separately from the document body; the document holds a metadata stub
  • Lazy-loaded — blob content is not read from disk until .content / .content is accessed
  • Replicated separately from documents; large blobs do not block document sync
  • Content type (MIME type) is required and used by Sync Gateway for filtering

Replication

The Replicator syncs one or more collections to a remote endpoint (Sync Gateway or Capella App Services).

Replicator types:

Type Direction
PUSH_AND_PULL Bidirectional (default for most apps)
PUSH Local → remote only
PULL Remote → local only

Continuous vs one-shot:

  • continuous = true — keeps a persistent connection; reconnects automatically
  • continuous = false — syncs once then stops; use for background fetch

Activity levels:

Level Meaning
CONNECTING Establishing connection
BUSY Actively transferring documents
IDLE Connected, no pending changes
OFFLINE No network; will retry
STOPPED Stopped (error or explicit stop)

Filters:

  • pushFilter — called for each local document before it is pushed; return false to skip
  • pullFilter — called for each remote document before it is saved locally; return false to reject

Always call replicator.stop() and remove the change listener token when the component is destroyed to release the network connection.


Authentication

Method When to use
BasicAuthenticator Username/password (Sync Gateway local users)
SessionAuthenticator Sync Gateway session token (obtained via REST login)
Client TLS cert Mutual TLS with Sync Gateway EE

Credential storage — never hardcode

Sync Gateway credentials must be retrieved at runtime from the platform secure store, not embedded in source code or BuildConfig/Info.plist constants baked into the binary.

Platform API Dependency
Android EncryptedSharedPreferences androidx.security:security-crypto
iOS / macOS SecItemCopyMatching Security.framework (built-in)

Android — write credentials (on login):

// androidx.security:security-crypto:1.1.0+
val masterKey = MasterKey.Builder(context)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
val prefs = EncryptedSharedPreferences.create(
    context, "sg_creds", masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
prefs.edit().putString("sg_username", username).putString("sg_password", password).apply()

Android — read credentials (before replicator start):

val username = prefs.getString("sg_username", null)!!
val password = prefs.getString("sg_password", null)!!

iOS — write credentials (on login):

// Security.framework — no additional dependency
func keychainWrite(key: String, value: String) {
    let data = value.data(using: .utf8)!
    let query: [String: Any] = [
        kSecClass as String:       kSecClassGenericPassword,
        kSecAttrAccount as String: key,
        kSecValueData as String:   data
    ]
    SecItemDelete(query as CFDictionary)  // remove existing before add
    SecItemAdd(query as CFDictionary, nil)
}

iOS — read credentials (before replicator start):

func keychainRead(key: String) -> String? {
    let query: [String: Any] = [
        kSecClass as String:       kSecClassGenericPassword,
        kSecAttrAccount as String: key,
        kSecReturnData as String:  true
    ]
    var result: AnyObject?
    guard SecItemCopyMatching(query as CFDictionary, &result) == errSecSuccess,
          let data = result as? Data else { return nil }
    return String(data: data, encoding: .utf8)
}

Never store credentials in SharedPreferences (Android) or UserDefaults (iOS) — these are not encrypted at rest.


Database Encryption (Enterprise Edition only)

Encrypts the entire .cblite2 file at rest using AES-256. The encryption key must be provided on every open. Losing the key means losing the data — store it in the platform keychain (Android Keystore / iOS Keychain).


Edition Comparison

Feature Community (CE) Enterprise (EE)
CRUD, SQL++, live queries
Full-text search
Replication
Database encryption
Vector search
P2P sync (URLEndpointListener)
Delta sync