本文へ移動
cccskills
無料GitHub で公開

ndk-batch-event-queries

Optimize Nostr relay queries using NDK batch fetching. Use when: (1) Checking existence of many events one-by-one is slow, (2) Loop with individual fetchEvents calls causing N+1 query problem, (3) Need to verify multiple addressable events (Kind 30000+) exist. NDK's fetchEvents accepts arrays for tag filters (#d, #p, #e, authors), enabling batch queries that reduce hundreds of round-trips to a single request.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md3.9 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

NDK Batch Event Queries

Problem

When checking if many Nostr events exist (e.g., 300 videos for a user), querying one-by-one causes hundreds of sequential relay round-trips, making the operation extremely slow (minutes instead of seconds).

Context / Trigger Conditions

  • Loop with await fetchEvents() inside, checking events individually
  • Processing takes minutes when it should take seconds
  • Checking existence of addressable events (Kind 30000-39999) by d-tag
  • Need to find which items from a list already exist on a relay

Solution

NDK's fetchEvents filter accepts arrays for most fields. Instead of:

// SLOW: 300 sequential queries
for (const id of vineIds) {
  const exists = await ndk.fetchEvents({
    kinds: [34236],
    authors: [pubkey],
    "#d": [id],  // Single value
  });
}

Use a batch query:

// FAST: 1-3 queries (chunked if needed)
const CHUNK_SIZE = 100;  // Relays may limit query size
const existingIds = new Set<string>();

for (let i = 0; i < vineIds.length; i += CHUNK_SIZE) {
  const chunk = vineIds.slice(i, i + CHUNK_SIZE);
  const events = await ndk.fetchEvents({
    kinds: [34236],
    authors: pubkeys,  // Can also be an array
    "#d": chunk,       // Array of d-tag values
  });

  for (const event of events) {
    const dTag = event.tags.find(t => t[0] === "d");
    if (dTag?.[1]) existingIds.add(dTag[1]);
  }
}

// O(1) lookup in processing loop
for (const id of vineIds) {
  if (existingIds.has(id)) continue;  // Skip existing
  // Process new items...
}

Key Points

  1. Array filters: #d, #p, #e, authors all accept arrays
  2. Chunk size: Use 50-100 items per query to avoid relay limits
  3. Multiple authors: Pass array of pubkeys if checking across users
  4. Extract results: Parse the d-tag from returned events to build a Set

Verification

  • Processing time drops from minutes to seconds
  • Total relay connections decrease dramatically
  • Same results as individual queries (verified by comparison)

Example

Real-world application - checking 294 videos across 2 pubkeys:

async videosExistBatch(pubkeys: string[], vineIds: string[]): Promise<Set<string>> {
  await this.connect();
  const existingIds = new Set<string>();
  const CHUNK_SIZE = 100;

  for (let i = 0; i < vineIds.length; i += CHUNK_SIZE) {
    const chunk = vineIds.slice(i, i + CHUNK_SIZE);
    const events = await this.ndk.fetchEvents({
      kinds: [34236],
      authors: pubkeys,
      "#d": chunk,
    });

    for (const event of events) {
      const dTag = event.tags.find((t) => t[0] === "d");
      if (dTag && dTag[1]) {
        existingIds.add(dTag[1]);
      }
    }
  }

  return existingIds;
}

Usage:

const vineIds = vines.map(v => v.vine_id);
const existingVineIds = await relay.videosExistBatch([pubkey, oldPubkey], vineIds);
console.log(`Found ${existingVineIds.size}/${vineIds.length} already on relay`);

Notes

  • Some relays may have stricter limits on query size; adjust CHUNK_SIZE accordingly
  • The buffered queries feature in NDK can also help with component-level batching
  • For very large sets, consider parallel chunk requests with Promise.all
  • This pattern works for any tag-based lookup, not just #d tags

References

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp). Use when: (1) Media moderation, transcoding, or analysis silently skips files from Blossom or content-addressed storage servers, (2) URL extraction from Nostr event tags (imeta, r tags) drops URLs without recognized extensions, (3) CDN fallback URLs append .mp4 but the actual server uses extensionless content-addressed paths like /{sha256}. Common in Nostr video events (kind 34236) where different clients use different URL formats.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

divinevideo のスキルをすべて見る

このスキルの問題を報告する