CosmosQL
Guide

Creating Documents

Learn how to create and insert documents into CosmosDB with CosmosQL

Complete guide to inserting documents into CosmosDB.

Navigation:


Single Document

Use when: Creating one document at a time.

Example scenario: User registration.

const newUser = await db.users.create({
  data: {
    id: 'user_123',
    email: 'john@example.com',
    name: 'John Doe',
    age: 30,
    createdAt: new Date()
    // Optional fields with defaults are automatically applied
  }
});
// Returns: Fully typed User object

What happens:

  1. CosmosQL generates a POST request to CosmosDB REST API
  2. Document is stored in the partition determined by email
  3. Return value is fully typed based on your schema

Cost: ~5 RU per document

Default Values

Use when: Your schema defines defaults for optional fields.

const users = container('users', {
  id: field.string(),
  email: field.string(),
  isActive: field.boolean().default(true), // Default value
  createdAt: field.date()
}).partitionKey('email');

// No need to provide isActive
const user = await db.users.create({
  data: {
    id: 'user_123',
    email: 'john@example.com',
    createdAt: new Date()
    // isActive automatically true
  }
});

Bulk Operations

Use when: Creating multiple documents in one request.

Requirement: All documents MUST share the same partition key.

Why: CosmosDB batch operations only work within a single partition.

Example scenario: Importing user posts.

await db.posts.createMany({
  data: [
    { id: 'post_1', userId: 'user_123', title: 'First', content: '...' },
    { id: 'post_2', userId: 'user_123', title: 'Second', content: '...' },
    { id: 'post_3', userId: 'user_123', title: 'Third', content: '...' }
  ],
  partitionKey: 'user_123' // Must be same for all documents
});

Cost: ~5 RU per document (same as single creates)
Performance: Single HTTP request vs multiple

Error handling: If any document fails, none are created (atomic within partition).

Best Practices

1. Always Provide IDs Explicitly

// ✅ Good: Explicit ID
const user = await db.users.create({
  data: {
    id: `user_${Date.now()}`, // Predictable
    email: 'user@example.com',
    // ...
  }
});

2. Use Meaningful IDs

// ✅ Good: Human-readable
'user_john@example.com'
'order_2024-01-15-abc123'

// ❌ Bad: Random UUIDs (unless you need them)
'a3f5b8c2-d4e6-7890-abcd-ef1234567890'

3. Set Timestamps Explicitly

const user = await db.users.create({
  data: {
    id: 'user_123',
    email: 'john@example.com',
    createdAt: new Date(), // Server time
    updatedAt: new Date()
  }
});

Error Handling

try {
  const user = await db.users.create({
    data: {
      id: 'user_123',
      email: 'john@example.com',
      // ...
    }
  });
} catch (error) {
  if (error.code === 409) {
    // Document with this ID already exists
    console.error('User already exists');
  } else if (error.code === 429) {
    // Rate limit exceeded
    console.error('Rate limit exceeded, please retry');
  } else {
    console.error('Failed to create user:', error);
  }
}

Common Patterns

Pattern: Multi-Tenant Applications

// Partition by tenant ID
const posts = container('posts', {
  id: field.string(),
  tenantId: field.string(),
  title: field.string(),
  // ...
}).partitionKey('tenantId');

// Create posts scoped to a tenant
await db.posts.createMany({
  data: [
    { id: 'post_1', tenantId: 'tenant_abc', title: '...' },
    { id: 'post_2', tenantId: 'tenant_abc', title: '...' }
  ],
  partitionKey: 'tenant_abc'
});

Pattern: Hierarchical Data

// Create parent-child relationships
const category = await db.categories.create({
  data: {
    id: 'cat_tech',
    name: 'Technology',
    parentId: null,
    createdAt: new Date()
  }
});

const subcategory = await db.categories.create({
  data: {
    id: 'cat_tech_ai',
    name: 'Artificial Intelligence',
    parentId: 'cat_tech',
    createdAt: new Date()
  }
});

Next Steps