
Product
Rust Support Now in Beta
Socket's Rust support is moving to Beta: all users can scan Cargo projects and generate SBOMs, including Cargo.toml-only crates, with Rust-aware supply chain checks.
@mkeen/rxcouch
Advanced tools
📀 Universal
RxJS powers this real-time CouchDB client written in TypeScript that runs in the browser or nodejs. The change feed is handled automatically. Everything's a BehaviorSubject
, so you get two-way binding for free. Enough said.
RxJS 6+
CouchDB 2.3+, CouchDB 3.0+
NPM: npm install @mkeen/rxcouch
Yarn: yarn install @mkeen/rxcouch
import { CouchDB } from '@mkeen/rxcouch';
const couchDbConnection = new CouchDB(
{
dbName: 'people',
}
);
CouchDB is initialized with: (RxCouchConfig, AuthorizationBehavior?, Observable<CouchDBCredentials>?)
An RxCouchConfig
looks like this by default:
{ host
: 'localhost'
port
: 5984
ssl
: false
trackChanges
: true,
dbName
: '_users' }
CouchDB supports Basic Auth, Cookies, and JWT authentication schemes. This library supports Cookies or JWT (bearer token). For development purposes only, this library also supports open installs of couchdb without security.
Let's take a look at how to initialize RxCouch for connecting to a CouchDB database that has Cookie Authentication configured.
import { BehaviorSubject } from 'rxjs';
import { CouchDB,
CouchSession,
AuthorizationBehavior } from '@mkeen/rxcouch';
const couchSession: CouchSession = new CouchSession(
AuthorizationBehavior.cookie,
`${COUCH_SSL? 'https://' : 'http://'}${COUCH_HOST}:${COUCH_PORT}/_session`,
new BehaviorSubject({username: 'username', password: 'password'}}),
);
const couchDbConnection = new CouchDB(
{
dbName: 'people',
host: 'localhost',
trackChanges: true,
},
couchSession
);
//...
The big detail to note here is that the final argument passed to the CouchSession initializer is an Observable
. In this example it's hardcoded. In a real-world implementation, you'll create an Observable
that emits when a user submits a login form, or when a configuration value is read, and pass that Observable
into the initializer.
It's common and recommended to share a single session instance across several CouchDB instances.
Since we're hardcoding the credentials Observable
argument, the above example will result in an authentication attempt being made to the speficied CouchDB host (without using HTTPS) immediately.
To determine which user (if any) is currently logged into CouchDB, you can call the session()
function. session
returns an Observable
that emits a CouchDBSession
.
//...
couchDbConnection.session().subscribe((session: CouchDBSession) => {
console.log('Currently session info: ', session);
});
If you're using CouchDB to authenticate users in your application, you could call session
when your app is initialized in order to determine if a user is logged in, and if so, any other information stored in the _users
document.
Whether authentication is used or not, a document is always returned to you by RxCouch in the form a BehaviorSubject
which provides a real-time two-way data binding with the document.
interface Person {
name: string;
email?: string;
phone?: string;
}
const myDocument: BehaviorSubject<Person> = couchDbConnection.doc('778...05b');
myDocument.subscribe((document: Person) => {
console.log('Most recent person: ', document);
});
//...
Most recent person: { _id: "7782f0743bee05005a548ba8af00205b", _rev: "10-bcaab49ec87c678686984d1c4873cd3e", name: 'Mike" }
//...
const myCompletelyChangedDocument = {
name: 'some new name here',
email: 'mwk@mikekeen.com',
phone: '323-209-5336'
}
myDocument.next(myCompletelyChangedDocument);
Most recent person: { _id: "7782f0743bee05005a548ba8af00205b", _rev: "11-bf3003bb5f63b875db4284f319a0b918", name: "some new name here", email: "mwk@mikekeen.com", phone: "323-209-5336"}
In the above example, a document was fetched by its _id
. The doc()
function alternatively accepts an object as an argument. If an object is passed in, one of two things will happen:
_id
and _rev
field, the rest of the fields in the object will be used to update the document that matches the _id
._id
and a _rev
field, then a new document will be created based on the fields contained in the object passed.Whichever of the above happens, doc
returns a BehaviorSubject
that will reflect all future changes to the relevant document, and pass all changes upstream when .next()
is called.
//...
const newlyCreatedPerson = couchDbConnection.doc({
name: 'tracy',
email: 'tracy@company.com',
phone: '323-209-5336'
}).subscribe((doc: Person) => {
console.log('Person Feed: ', doc);
});
Person Feed: {"_id": "7782f0743bee05005a548ba8af00b4f5", "_rev": "1-2fee21d51258845545ea6506ab138919", "name": "tracy", "email": "tracy@company.com", "phone": "323-209-5336"}
There are two ways to modify a document that already exists in CouchDB.
One way, is to simply pass a modified version of the existing document to doc
like in the example below:
//...
couchDbConnection.doc({
_id: '7782f0743bee05005a548ba8af00b4f5',
_rev: '1-2fee21d51258845545ea6506ab138919',
name: 'tracy',
email: 'tracy@company-modified.com',
phone: '323-209-5336'
}).subscribe((doc) => {
console.log('Document Modified: ', doc);
})
Document Modified: { "_id": "7782f0743bee05005a548ba8af00b4f5", "_rev": "2-e654adf15f28b99f26ae1f0dbe8e7c36", "name": "tracy", "email": "tracy@company-modified.com", "phone": "323-209-5336" }
Person Feed: {"_id": "7782f0743bee05005a548ba8af00b4f5", "_rev": "2-e654adf15f28b99f26ae1f0dbe8e7c36", "name": "tracy", "email": "tracy@company-modified.com", "phone": "323-209-5336" }
Another way to modify a document that already exists in CouchDB is to just call next
on an already fetched document's BehaviorSubject
.
//..
newlyCreatedPerson.next({
name: 'tracy Modified!',
email: 'tracy@company-modified-again.com',
phone: '323-209-5336'
});
Person Feed: {"_id": "7782f0743bee05005a548ba8af00b4f5", "_rev": "3-8da970f593132c80ccee83fc4708ce33", "name": "tracy Modified!", "email": "tracy@company-modified-again.com", "phone": "323-209-5336" }
RxCouch exposes find
from CouchDB
that uses CouchDB Selector Syntax to make queries, and returns a list of matching documents. Warning: Documents returned are not BehaviorSubject
s!
Call find
with (CouchDBFindQuery)
.
An CouchDBFindQuery
, when passed into find
, should conform to CouchDB Selector Syntax. It can have the following optional properties of the following types:
selector: CouchDBFindSelector
limit: number
skip: number
sort: CouchDBFindSort[]
fields: string[]
use_index: string | []
r: number
bookmark: string
update: boolean
stable: boolean
stale: string
execution_stats: boolean
A call to find
will return an Observable
that will emit a list of documents that match the passed query.
//...
couchDbConnection.find({
selector: {
name: 'tracy'
}
}).subscribe((matchingPeople: Person[]) => {
console.log('Matching people: ', matchingPeople);
});
Matching people: [{ "_id": "7782f0743bee05005a548ba8af00b4f5", "_rev": "3-8da970f593132c80ccee83fc4708ce33", "name": "tracy Modified!", "email": "tracy@company-modified-again.com", "phone": "323-209-5336" }]
//...
couchDbConnection.find({
selector: {
name: 'some new name here'
}
}).subscribe((matchingPeople: Person[]) => {
const documentFeeds = matchingPeople.map((person: Person) => {
return couchDbConnection.doc(matchingPeople)
});
documentFeeds.forEach((feed) => {
feed.subscribe(
(document: Person) => console.log('Latest person: ', document)
);
});
});
Latest person: { "_id": "7782f0743bee05005a548ba8af00b4f5", "_rev": "3-8da970f593132c80ccee83fc4708ce33", "name": "tracy Modified!", "email": "tracy@company-modified-again.com", "phone": "323-209-5336" }
Documents are automatically cached and then tracked for changes. CouchDBDocumentCollection
handles both caching and change tracking.
Instances of CouchDB
have a method called doc
. Any documents that flow through doc
are cached in a CouchDBDocumentCollection
. They can later be retrieved by _id in the form of a BehaviorSubject
that supports two way binding. A hash of the document is indexed (by document id) for change tracking purposes.
Before document changes are propagated either to or from a BehaviorSubject
, the potentially changed document is hashed and compared against a previously indexed hash of the document. If the hashes don't match, the document has changed, and it will be passed into the next
method of the relavent indexed BehaviorSubject
. Finally, the indexed hash entry for the document will be updated.
🇺🇸
FAQs
Real Time RxJs Based CouchDB Client
The npm package @mkeen/rxcouch receives a total of 1 weekly downloads. As such, @mkeen/rxcouch popularity was classified as not popular.
We found that @mkeen/rxcouch demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket's Rust support is moving to Beta: all users can scan Cargo projects and generate SBOMs, including Cargo.toml-only crates, with Rust-aware supply chain checks.
Product
Socket Fix 2.0 brings targeted CVE remediation, smarter upgrade planning, and broader ecosystem support to help developers get to zero alerts.
Security News
Socket CEO Feross Aboukhadijeh joins Risky Business Weekly to unpack recent npm phishing attacks, their limited impact, and the risks if attackers get smarter.