# Dexie IndexedDB Schema for Caching Articles and Comments in WeChat Article Exporter

> Learn the Dexie IndexedDB schema for caching WeChat articles and comments in the WeChat Article Exporter. Discover efficient client-side data persistence strategies.

- Repository: [公众号文章工具箱/wechat-article-exporter](https://github.com/wechat-article/wechat-article-exporter)
- Tags: internals
- Published: 2026-05-26

---

**The WeChat Article Exporter uses a Dexie IndexedDB database named `exporter.wxdown.online` with two main tables—`article` (composite key `${fakeid}:${aid}`) and `comment` (primary key `url`)—to persistently cache fetched WeChat data client-side.**

The [wechat-article-exporter](https://github.com/wechat-article/wechat-article-exporter) is a Nuxt-based open-source tool for archiving WeChat public account content. To eliminate redundant API requests and enable offline browsing, the application implements a client-side caching layer using Dexie.js, a minimalistic IndexedDB wrapper. The schema definition and versioning logic are centralized in [`store/v2/db.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/db.ts), while high-level data access methods reside in [`store/v2/article.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/article.ts) and [`store/v2/comment.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/comment.ts).

## Database Configuration

The IndexedDB instance is initialized as a constant `db` object with strict TypeScript typing. The database name is hardcoded as **`exporter.wxdown.online`** in [`store/v2/db.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/db.ts).

```ts
const db = new Dexie('exporter.wxdown.online') as Dexie & {
  article: Table<ArticleAsset, string>;
  comment: EntityTable<CommentAsset, 'url'>;
  // ... other tables
};

```

The schema undergoes versioned upgrades. Version 1 establishes base tables, while Version 2 adds the `fakeid` index to the `comment` table for efficient account-based lookups.

## Article Table Schema

The **`article`** table stores metadata and content for individual WeChat articles. Its schema is defined across database versions as follows:

- **Primary Key**: Composite string `` `${fakeid}:${aid}` `` (supplied explicitly during insertion, not auto-generated)
- **Indexes**: `fakeid`, `create_time`, `link`

```ts
// store/v2/db.ts
db.version(1).stores({
  article: ', fakeid, create_time, link', // empty slot before comma = manual primary key
});

db.version(2).stores({
  article: ', fakeid, create_time, link', // unchanged in v2
});

```

The empty string before the first comma in the schema declaration indicates Dexie should not auto-increment the primary key; instead, the application supplies the composite key `${fakeid}:${article.aid}` when calling `db.article.put()`.

## Comment Table Schema

The **`comment`** table caches comment threads associated with articles. Unlike the article table, it uses a natural key derived from the comment's URL.

- **Primary Key**: `url` (the absolute URL of the comment resource)
- **Indexes**: `url` (v1), `fakeid` (added in v2)

```ts
// store/v2/db.ts
db.version(1).stores({
  comment: 'url',
});

db.version(2).stores({
  comment: 'url, fakeid', // Enables filtering comments by public account
});

```

The addition of the `fakeid` index in Version 2 allows the application to query all comments belonging to a specific public account without scanning the entire table.

## Programmatic Usage

The repository provides strongly-typed helper functions in [`store/v2/article.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/article.ts) and [`store/v2/comment.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/comment.ts) to interact with these tables.

### Inserting or Updating Articles

To cache an article, generate the composite primary key and call `put()` with the key as the second argument:

```ts
import { db } from '@/store/v2/db';
import type { ArticleAsset } from '@/store/v2/article';

async function cacheArticle(fakeid: string, article: ArticleAsset) {
  const primaryKey = `${fakeid}:${article.aid}`;
  await db.article.put(
    { ...article, fakeid, _status: '' }, 
    primaryKey
  );
}

```

This pattern is implemented in [`store/v2/article.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/article.ts) around lines 29–31.

### Querying Articles by Account

Retrieve articles for a specific public account (`fakeid`) created before a timestamp, sorted newest-first:

```ts
async function getArticlesBefore(fakeid: string, createTime: number) {
  return db.article
    .where('fakeid')
    .equals(fakeid)
    .and(a => a.create_time < createTime)
    .reverse()
    .sortBy('create_time');
}

```

This query leverages the `fakeid` and `create_time` compound indexes defined in the schema.

### Caching Comments

Storing comments requires no manual key generation because `url` is defined as the primary key in the Dexie schema:

```ts
import { db } from '@/store/v2/db';
import type { CommentAsset } from '@/store/v2/comment';

async function cacheComment(comment: CommentAsset) {
  await db.comment.put(comment); // Primary key is comment.url
}

```

See [`store/v2/comment.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/comment.ts) lines 14–18 for the reference implementation.

### Retrieving Comments by URL

Fetch a single cached comment using its natural key:

```ts
async function getComment(url: string) {
  return db.comment.get(url);
}

```

This operation performs a direct primary key lookup in IndexedDB.

## Summary

- The **Dexie IndexedDB schema** is defined in [`store/v2/db.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/db.ts) and uses the database name `exporter.wxdown.online`.
- **Article records** use a composite primary key `` `${fakeid}:${aid}` `` and are indexed on `fakeid`, `create_time`, and `link`.
- **Comment records** use the comment `url` as the primary key; Version 2 adds a `fakeid` index for account-scoped queries.
- Always provide the composite key explicitly when calling `db.article.put()` to avoid auto-increment collisions.
- Query performance relies on Dexie's `where()` clauses targeting the defined indexes rather than full-table scans.

## Frequently Asked Questions

### Why does the article table use a composite primary key instead of an auto-incrementing ID?

The application manually constructs the primary key as `` `${fakeid}:${aid}` `` to ensure uniqueness across different WeChat public accounts while maintaining a deterministic lookup mechanism. This composite key guarantees that re-fetching the same article from the WeChat API overwrites the existing cache entry rather than creating a duplicate, as implemented in [`store/v2/article.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/store/v2/article.ts).

### What changed between schema Version 1 and Version 2?

Version 2 added the `fakeid` index to the `comment` table (`'url, fakeid'`), whereas Version 1 only indexed the `url` field. This change enables efficient retrieval of all comments belonging to a specific public account using `db.comment.where('fakeid').equals(...)`, which was not performantly possible in Version 1.

### How does Dexie handle the empty string in the article schema definition?

In Dexie schema notation, an empty string before the first comma (as seen in `', fakeid, create_time, link'`) signals that the primary key is not auto-generated. The application must supply the primary key explicitly during `put()` or `add()` operations. If omitted, Dexie would throw an error requiring the key parameter.

### Can I query articles without knowing the fakeid?

No. The current schema requires the `fakeid` (public account identifier) to construct the primary key and to use the `fakeid` index. To query across all accounts, you would need to perform a full table scan using `db.article.toArray()`, which is discouraged for performance reasons on large datasets.