Skip to main content

Adding Data

Fast and responsive user experience using optimistic updates.

Why Use Mutations

You need to create new records or update existing ones in your database. The Squid Client SDK provides insert and update operations that apply changes optimistically on the client for instant UI feedback, then sync with the server asynchronously.

Quick Start

Client code
// Insert a new document
await squid.collection<User>('users').doc('user_1').insert({
name: 'Alice',
email: 'alice@example.com',
});

Overview

Unless being run in a transaction, all inserts and updates return a Promise which resolves once the mutation is applied on the server.

Inserts and updates are applied optimistically locally and reflect immediately on the client. The changes are then sent to the server asynchronously to ensure a consistent, clean data state.

There are three types of write mutations: insert, update, and setInPath. Each is performed on a document reference.

Core Concepts

Insert

Insert is used for creating a new document. To insert a new document into a collection, call the insert method on a DocumentReference and pass in the new document data as an argument:

Client code
try {
await squid.collection<User>('users').doc('new_user_id').insert({
name: 'John Doe',
email: 'johndoe@example.com',
});
console.log('User added successfully');
} catch (error) {
console.error(`Failed to add user ${error}`);
}
Tip

The backend security rules enable you to control who can perform each mutation in a granular way. These rules receive a MutationContext as a parameter, which contains all the needed details about the mutation including the snapshot of the document before and after the change. Read more about security rules to understand how to write them.

Insert many

The insertMany method is used for efficiently inserting and/or updating multiple documents at once. The following example adds an array of new user documents:

Client code
const newDocuments = [
{
id: 'new_user_id1',
data: {
name: 'John Doe',
email: 'johndoe@example.com',
},
},
{
id: 'new_user_id2',
data: {
name: 'Jan Smith',
email: 'jansmith@example.com',
},
},
];

try {
await squid.collection<User>('users').insertMany(newDocuments);
console.log('Users added successfully');
} catch (error) {
console.error(`Failed to add users ${error}`);
}

Update

To update a document, call the update method on a DocumentReference and pass in an object that contains the partial update data as an argument:

Client code
try {
await squid
.collection<User>('users')
.doc('existing_user_id')
.update({ email: 'new_email@example.com' });
console.log('User updated successfully');
} catch (error) {
console.error(`Failed to update user ${error}`);
}

Set in Path

You can also update a specific property of a document by calling the setInPath method on a DocumentReference and passing the path to the property and the new value as arguments. Use dot notation to specify nested properties in the path:

Client code
const userRef = squid.collection<User>('users').doc('existing_user_id');

try {
await userRef.setInPath('address.street', 'Main');
console.log('Updated successfully');
} catch (error) {
console.error(`Failed to update user ${error}`);
}

Error Handling

ErrorCauseSolution
Security rule rejectionThe mutation was blocked by security rulesVerify the user has write permission for the collection
Document already existsCalling insert on a document ID that already exists in some connector typesUse update for existing documents, or use a unique ID
Invalid data shapeThe inserted data does not match the collection schemaEnsure the data object matches the expected schema and types
Network errorThe server could not be reached to confirm the mutationThe optimistic update is rolled back; retry the operation

Best Practices

  1. Use update() for partial changes to send only the fields that changed, rather than re-inserting the entire document.

  2. Use setInPath() for deeply nested updates to modify a single nested field without touching the rest of the document:

    Client code
    // Update only the city without affecting other address fields
    await userRef.setInPath('address.city', 'New York');
  3. Use insertMany() for bulk operations to reduce the number of round trips to the server.

  4. Wrap related mutations in a transaction when you need atomicity across multiple documents.

  5. Handle errors on mutations since the server may reject changes that pass client-side validation but fail security rules or schema checks.