packages/db/docs/02-Collections.md

Summary

Maintainability
Test Coverage
---
title: Collections
sections: ["Database"]
---

A collection is a grouping of `@valkyr/db` documents. Documents within a collection can have different fields. A collection is the equivalent of a table in a relational database system.

In `@valkyr/db` there is no central `database` instance. Instead we simply create a collection and assign it to a variable of our choosing. A collection will automatically resolve and persist data when performing operations against it, so no preload step is required when interacting with a collection.

**Example**

```ts
import { Collection, Document, IndexedDbAdapter } from "@valkyr/db";

type UserDocument = Document & {
  name: string;
  email: string;
};

const users = new Collection<UserDocument>("users", new IndexedDbAdapter());
```

---

# Insert Documents

`@valkyr/db` provides the following methods of inserting `documents` into a collection:

---

## .insertOne

Inserts a single document and returns a insert result.

**Definition**

```ts
collection.insertOne(document: PartialDocument<D>): Promise<InsertResult | InsertException>;
```

**Example**

```ts
const result = await users.insertOne({ name: "John", email: "john@doe.com", views: 0 });
```

**Types**

```ts
type InsertResult = {
  acknowledged: true;
  insertedId: string;
};

type InsertException = {
  acknowledged: false;
  exception: Error;
};
```

---

## .insertMany

Inserts multiple documents and returns a insert many result.

**Definition**

```ts
collection.insertMany(documents: PartialDocument<D>[]): Promise<InsertManyResult>;
```

**Example**

```ts
const result = await users.insertMany([
  { name: "John", email: "john@doe.com", views: 0 },
  { name: "Jane", email: "jane@doe.com", views: 0 }
]);
```

**Types**

```ts
type InsertManyResult = {
  acknowledged: boolean;
  insertedIds: string[];
  exceptions: Error[];
};
```

---

# Query Documents

`@valkyr/db` provides the following methods of querying `documents` in a collection:

Additional information can be found through [mongodb](https://www.mongodb.com/docs/v5.0/tutorial/query-documents) documentation.

`@valkyr/db` uses [mingo](https://github.com/kofrasa/mingo) as the query driver, an excellent solution brining mongodb queries to TypeScript. Please refer to [differences from mongodb](https://github.com/kofrasa/mingo#differences-from-mongodb) to familiarize yourself with query differences.

---

## .findById

Returns `document` that satisfies the specified `id`.

**Definition**

```ts
collection.findById(id: string): Promise<Document | undefined>;
```

This is a specialized method which reads the record straight from the document `storage` map. This is the most optimized method for fetching a known document and is the only query method that does not utilize [mingo](https://github.com/kofrasa/mingo).

**Example**

```ts
const user = await users.findById("xyz");
```

---

## .find

Returns documents that satisfies the specified query `criteria` and `options` on the collection.

**Definition**

```ts
collection.find(criteria: RawObject = {}, options?: Options): Promise<Document[]>;
```

See [mongo.find()](https://www.mongodb.com/docs/v4.4/reference/method/db.collection.find) for additional information.

**Example**

```ts
const users = await users.find({ name: "John" });
```

**Types**

```ts
type Options = {
  sort?: {
    [key: string]: 1 | -1;
  };
  skip?: number;
  limit?: number;
};
```

---

## .findOne

Returns one `document` that satisfies the specified query `criteria` and `options` on the collection. If multiple documents satisfy the query, this method returns the first `document` according to the natural order which reflects the order of documents on the disk. In capped collections, natural order is the same as insertion order. If no `document` satisfies the query, the method returns `undefined`.

**Definition**

```ts
collection.findOne(criteria: RawObject = {}, options?: Options): Promise<Document | undefined>;
```

See [mongo.findOne()](https://www.mongodb.com/docs/v4.4/reference/method/db.collection.findOne) for additional information.

**Example**

```ts
const user = await users.findOne({ name: "John" });
```

**Types**

```ts
type Options = {
  sort?: {
    [key: string]: 1 | -1;
  };
  skip?: number;
  limit?: number;
};
```

---

## .count

Returns the count of documents that would match a `find()` query for the collection. The `collection.count()` method does not perform the `find()` operation but instead counts and returns the number of results that match a query.

**Definition**

```ts
collection.count(criteria: RawObject = {}): Promise<number>;
```

**Example**

```ts
const userCount = await users.count({ email: { $regex: /@test\.com/i } });
```

---

## .query

Selects documents in a collection that satisfies the specified query `criteria` and returns a cursor to the selected documents.

**Definition**

```ts
collection.query(criteria: RawObject = {}): Promise<Cursor>;
```

**Example**

```ts
const cursor = await users.query({ email: { $regex: /john@/i } });
// perform additional filtering behavior on the cursor
const users = cursor.all();
```

---

# Observe Documents

Subscriptions provides a observation layer for `.find` and `.findOne` type data filtering and wraps it in a `rxjs` observer instance. Any time the collection sees changes to data matching the observation filter the observer subscription is notified and forwards the changes.

---

## .observe

Returns observable which observes documents that satisfies the specified query `criteria` and `options` on the collection.

**Definition**

```ts
collection.observe(criteria: RawObject = {}, options?: Options): Observable<Document[]>;
```

**Example**

```ts
const subscription = users.observe({ name: "John" }).subscribe((users) => {
  // list of users with name John
});
```

---

## .observeOne

Returns observable which observes document that satisfies the specified query `criteria` on the collection. If no `document` satisfies the query, the observer returns `undefined`.

**Definition**

```ts
collection.observeOne(criteria: RawObject = {}): Observable<Document | undefined>;
```

**Example**

```ts
const subscription = users.observeOne({ name: "Jane" }).subscribe((user) => {
  // closest user with name Jane
});
```

:::div{class="admonitions"}

Make sure to close the subscription when it is no longer needed or it will linger past its use. You can do this by simply executing the `.unsubscribe()` method on the `subscription` instance.

```ts
subscription.unsubscribe();
```

:::

---

# Update Documents

The update command modifies documents in a collection. A single update command can contain multiple update statements.

:::div{class="admonitions"}

**Supported Update Operations**

- [$set](https://www.mongodb.com/docs/v4.4/reference/operator/update/set/)
  - When accessing arrays use `ratings[0].rating` instead of `ratings.0.rating`
  - [$(update)](https://www.mongodb.com/docs/v4.4/reference/operator/update/positional/)
    - Update with Multiple Array Matches is not supported. [Example](https://www.mongodb.com/docs/v4.4/reference/operator/update/positional/#update-with-multiple-array-matches)
- [$unset](https://www.mongodb.com/docs/v4.4/reference/operator/update/unset/)
- [$push](https://www.mongodb.com/docs/v4.4/reference/operator/update/push/)
- [$pull](https://www.mongodb.com/docs/v4.4/reference/operator/update/pull/)

:::

---

## .updateOne

Update a document using the given filter.

**Definition**

```ts
collection.updateOne(criteria: RawObject, update: UpdateActions): Promise<UpdateResult>
```

**Example**

```ts
const result = await users.updateOne({ name: "John" }, { email: "john.doe@fixture.none" });
```

**Types**

```ts
type UpdateResult = {
  acknowledged: boolean;
  matchedCount: number;
  modifiedCount: number;
  exceptions: Error[];
};
```

---

## .updateMany

Updates all documents that match the specified filter for a collection.

**Definition**

```ts
collection.updateMany(criteria: RawObject, update: UpdateOperations): Promise<UpdateResult>;
```

**Example**

```ts
const result = await users.updateMany({ views: { $lt: 10 } }, { views: 10 });
```

**Types**

```ts
type UpdateResult = {
  acknowledged: boolean;
  matchedCount: number;
  modifiedCount: number;
  exceptions: Error[];
};
```

---

## .replaceOne

Replaces a single document within the collection based on the filter.

**Definition**

```ts
collection.replaceOne(criteria: RawObject, document: D): Promise<UpdateResult>;
```

**Example**

```ts
const result = await users.replaceOne(
  {
    name: "John"
  },
  {
    name: "Dave",
    email: "dave@doe.com",
    views: 0
  }
);
```

**Types**

```ts
type UpdateResult = {
  acknowledged: boolean;
  matchedCount: number;
  modifiedCount: number;
  exceptions: Error[];
};
```

---

# Remove Documents

The remove command deletes documents in a collection.

---

## .remove

Removes documents from a collection.

**Definition**

```ts
collection.remove(criteria: RawObject, options?: RemoveOptions): Promise<RemoveResult>;
```

**Example**

```ts
const result = await users.remove({ email: { $regex: /$@doe/i } });
```

**Types**

```ts
type RemoveResult = {
  acknowledged: boolean;
  deletedCount: number;
  exceptions: Error[];
};
```