Skip to content

update

The method allows updating a document. It’s available on Collection, Ref, and Doc.

The method returns Ref instance:

const ref = await db.users.update(userId, { name: "Alexander" });
//=> Ref<User>

Typesaurus accepts partial data. If the document doesn’t exist, it will throw an error.

It accepts a function as the argument that allows you to use the $ helper object:

await db.users.update(userId, ($) => ({
name: "Sasha",
updatedAt: $.serverDate(),
}));

Deep fields update

You can update individual fields, including nested ones, using $.field helper:

await db.users.update(userId, ($) => [
$.field("name").set("Sasha"),
$.field("address", "city").set("San Jose"),
]);

It allows you to update multiple disconnected fields at once.

When updating nested fields, make sure you use “safe paths” to prevent data inconsistency.

→ Read more about safe paths.

Builder mode

The update also allows you to use the builder mode, where you accumulate the update operations and then call run to execute them:

// Start building the update
const $ = db.users.update.build(userId);
$.field("updatedAt").set($.serverDate());
// ...Do something in between, including async operations
$.field("address", "city").set("San Jose");
// Run the update
await $.run();
// Ref<User>

Just like the function argument, the builder has the same set of helpers:

Variable model

When updating a variable model, you can only update using the complete data or partial shared data:

const db = schema(($) => ({
accounts: $.collection<[GitHubAccount, MicrosoftAccount, GoogleAccount]>(),
}));
interface GitHubAccount {
type: "github";
active: boolean;
userId: string;
}
interface MicrosoftAccount {
type: "microsoft";
active: boolean;
accountId: string;
}
interface GoogleAccount {
type: "google";
active: boolean;
email: string;
}
// OK! We're updating a shared field.
await db.accounts.update(accountId, {
active: true,
});
// OK! We're updating with complete data.
await db.accounts.update(accountId, {
type: "google",
active: true,
email: "example@example.com",
});
// Nope!
await db.accounts.update(accountId, {
// Email is only available for GoogleAccount
email: "example@example.com",
//=> Object literal may only specify known properties, and 'email' does not exist in type 'Arg<SharedShape3<GitHubAccount, MicrosoftAccount, GoogleAccount>, DocProps & { environment: RuntimeEnvironment; }>'.ts(2353)
});

You can also narrow the model before updating. Then, the partial update will be available:

const account = await db.accounts.get(accountId);
if (account) {
const googleAccount = account.narrow(
(data) => data.type === "google" && data,
);
await googleAccount?.update({
email: "example@example.com",
});
}

→ Read more about variable models.

$ helper

The argument function receives the $ helper object as the first argument that provides write helpers.

$ type is TypesaurusUpdate.Helpers.

The function can return a falsy value to skip the update:

const name = undefined;
// Will not update the document as the name is undefined
await db.users.update(userId, ($) => name && { name });
//=> undefined

A skipped update call will return undefined.

$.field

The helper allows to update individual fields, including nested ones:

interface User {
name: string;
address: {
city: string;
country: string;
};
}
await db.users.update(userId, ($) => [
$.field("name").set("Sasha"),
$.field("address", "city").set("San Jose"),
]);

You can return an array of helpers to update multiple fields at once. You also can return a single field:

await db.users.update(userId, ($) =>
$.field("address", "city").set("San Jose"),
);

If you return a falsy value, the update will be skipped:

const city = undefined;
await db.users.update(
userId,
($) => city && $.field("address", "city").set(city),
);
//=> undefined

$.field(...).set

The set function allows setting a value to a field. It always accepts the field type or corresponding system value produced by a help like $.serverDate():

await db.users.update(userId, ($) => $.field("name").set("Sasha"));

$.serverDate

To assign a server date to a field, use $.serverDate:

await db.users.update(userId, ($) => ({
name: "Sasha",
// Set updatedAt to the server date
updatedAt: $.serverDate(),
}));

It will assign the date when Firestore saves the document.

→ Read more about server dates.

$.remove

To remove a field, use $.remove:

interface User {
name: string;
avatar?: string;
}
await db.users.update(userId, ($) => ({
// Remove avatar field
avatar: $.remove(),
}));

Removing a field that is not optional will show you a type error.

$.increment

To increment a number field, use $.increment:

await db.users.update(userId, ($) => ({
// Increment the kudos field by 1
kudos: $.increment(1),
}));

The method is only available for the number fields.

$.arrayUnion

To add an item to an array field, use $.arrayUnion:

await db.users.update(userId, ($) => ({
// Add "cool" tag to the tags array
tags: $.arrayUnion("cool"),
}));

The method is only available for the array fields.

$.arrayRemove

To remove an item from an array field, use $.arrayRemove:

await db.users.update(userId, ($) => ({
// Remove the "cool" tag from the tags array
tags: $.arrayRemove("cool"),
}));

The method is only available for the array fields.

Options

as

You can tell Typesaurus that it’s safe to set dates to server dates by passing the as option ("server" | "client"):

import { Typesaurus } from "typesaurus";
interface User {
name: string;
updatedAt: Typesaurus.ServerDate;
}
// Can't assign Date to ServerDate
await db.users.update(userId, ($) => ({
name: "Sasha",
updatedAt: new Date(),
}));
//=> The types of 'updatedAt' are incompatible between these types.
//=> Type 'Date' is missing the following properties from type 'ValueServerDate': type, kind
// OK!
await db.users.update(
userId,
($) => ({
name: "Sasha",
// OK! We're on the server
updatedAt: new Date(),
}),
{ as: "server" },
);

By default, Typesaurus uses the "client" option.

The builder mode also accepts the as option:

const $ = db.users.update.build(userId, { as: "server" });
$.field("updatedAt").set(new Date());
await $.run();

→ Read more about server dates.