feat: kb both volumes
This commit is contained in:
+191
-27
@@ -49,6 +49,26 @@ function readAllJsonInDir(dir: string): unknown[] {
|
||||
.map((f) => readJson(path.join(dir, f)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert documents one at a time with a small delay every N docs.
|
||||
*
|
||||
* Uses insertOne to avoid BSON wire-protocol corruption that occurs
|
||||
* with insertMany on certain MongoDB server/proxy configurations.
|
||||
* A brief pause every 100 docs prevents connection overload.
|
||||
*/
|
||||
async function insertBatched(
|
||||
col: ReturnType<ReturnType<MongoClient["db"]>["collection"]>,
|
||||
docs: Record<string, unknown>[],
|
||||
) {
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
await col.insertOne(docs[i]);
|
||||
// Pause briefly every 100 docs to give the connection breathing room
|
||||
if ((i + 1) % 100 === 0) {
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -95,6 +115,17 @@ type CcVerse = {
|
||||
purport: string[];
|
||||
};
|
||||
|
||||
type ProseChapterJson = {
|
||||
book: string;
|
||||
volume: number;
|
||||
chapter?: number;
|
||||
title: string;
|
||||
type: string;
|
||||
slug?: string;
|
||||
order?: number;
|
||||
paragraphs: string[];
|
||||
};
|
||||
|
||||
type Sb1962Verse = {
|
||||
book_title: string;
|
||||
chapter: number;
|
||||
@@ -178,9 +209,7 @@ async function seedBg(db: ReturnType<MongoClient["db"]>) {
|
||||
}
|
||||
}
|
||||
|
||||
if (docs.length > 0) {
|
||||
await versesCol.insertMany(docs, { ordered: false });
|
||||
}
|
||||
await insertBatched(versesCol, docs);
|
||||
console.log(` ✅ BG: ${docs.length} verses`);
|
||||
}
|
||||
|
||||
@@ -227,14 +256,14 @@ async function seedSb(db: ReturnType<MongoClient["db"]>) {
|
||||
.filter((d) => fs.statSync(path.join(chaptersDir, d)).isDirectory())
|
||||
.sort();
|
||||
|
||||
const docs: Record<string, unknown>[] = [];
|
||||
const cantoDocs: Record<string, unknown>[] = [];
|
||||
|
||||
for (const chDir of chapterDirs) {
|
||||
const versesDir = path.join(chaptersDir, chDir, "verses");
|
||||
const verses = readAllJsonInDir(versesDir) as SbVerse[];
|
||||
|
||||
for (const v of verses) {
|
||||
docs.push({
|
||||
cantoDocs.push({
|
||||
book: "sb",
|
||||
division: String(v.canto),
|
||||
chapter: v.chapter,
|
||||
@@ -252,11 +281,9 @@ async function seedSb(db: ReturnType<MongoClient["db"]>) {
|
||||
}
|
||||
}
|
||||
|
||||
if (docs.length > 0) {
|
||||
await versesCol.insertMany(docs, { ordered: false });
|
||||
}
|
||||
totalCount += docs.length;
|
||||
console.log(` Canto ${cantoDir}: ${docs.length} verses`);
|
||||
await insertBatched(versesCol, cantoDocs);
|
||||
totalCount += cantoDocs.length;
|
||||
console.log(` Canto ${cantoDir}: ${cantoDocs.length} verses`);
|
||||
}
|
||||
|
||||
console.log(` ✅ SB: ${totalCount} verses`);
|
||||
@@ -305,14 +332,14 @@ async function seedCc(db: ReturnType<MongoClient["db"]>) {
|
||||
.filter((d) => fs.statSync(path.join(chaptersDir, d)).isDirectory())
|
||||
.sort();
|
||||
|
||||
const docs: Record<string, unknown>[] = [];
|
||||
const lilaDocs: Record<string, unknown>[] = [];
|
||||
|
||||
for (const chDir of chapterDirs) {
|
||||
const versesDir = path.join(chaptersDir, chDir, "verses");
|
||||
const verses = readAllJsonInDir(versesDir) as CcVerse[];
|
||||
|
||||
for (const v of verses) {
|
||||
docs.push({
|
||||
lilaDocs.push({
|
||||
book: "cc",
|
||||
division: v.lila,
|
||||
chapter: v.chapter,
|
||||
@@ -330,11 +357,9 @@ async function seedCc(db: ReturnType<MongoClient["db"]>) {
|
||||
}
|
||||
}
|
||||
|
||||
if (docs.length > 0) {
|
||||
await versesCol.insertMany(docs, { ordered: false });
|
||||
}
|
||||
totalCount += docs.length;
|
||||
console.log(` Līlā ${lilaDir}: ${docs.length} verses`);
|
||||
await insertBatched(versesCol, lilaDocs);
|
||||
totalCount += lilaDocs.length;
|
||||
console.log(` Līlā ${lilaDir}: ${lilaDocs.length} verses`);
|
||||
}
|
||||
|
||||
console.log(` ✅ CC: ${totalCount} verses`);
|
||||
@@ -397,12 +422,143 @@ async function seedSb1962(db: ReturnType<MongoClient["db"]>) {
|
||||
}
|
||||
}
|
||||
|
||||
if (docs.length > 0) {
|
||||
await versesCol.insertMany(docs, { ordered: false });
|
||||
}
|
||||
await insertBatched(versesCol, docs);
|
||||
console.log(` ✅ SB 1962: ${docs.length} verses`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Kṛṣṇa Book
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function seedKb(db: ReturnType<MongoClient["db"]>) {
|
||||
const introPath = path.join(LIB_DIR, "books", "kb", "intro.json");
|
||||
if (!fs.existsSync(introPath)) {
|
||||
console.log(" ⏭ KB intro.json not found, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const intro = readJson(introPath);
|
||||
|
||||
// Book meta
|
||||
const metaCol = db.collection("book_meta");
|
||||
await metaCol.deleteMany({ book: "kb" });
|
||||
await metaCol.insertOne({ book: "kb", data: intro });
|
||||
console.log(" 📖 KB book meta inserted");
|
||||
|
||||
// Prose chapters collection
|
||||
const proseCol = db.collection("prose_chapters");
|
||||
await proseCol.deleteMany({ book: "kb" });
|
||||
|
||||
const docs: Record<string, unknown>[] = [];
|
||||
|
||||
// Volume 1 intro segments
|
||||
const vol1IntroDir = path.join(LIB_DIR, "books", "kb", "vol-1", "intro");
|
||||
if (fs.existsSync(vol1IntroDir)) {
|
||||
const introFiles = fs
|
||||
.readdirSync(vol1IntroDir)
|
||||
.filter((f) => f.endsWith(".json"))
|
||||
.sort();
|
||||
|
||||
const introDocsV1: Record<string, unknown>[] = [];
|
||||
for (const file of introFiles) {
|
||||
const seg = readJson<ProseChapterJson>(path.join(vol1IntroDir, file));
|
||||
introDocsV1.push({
|
||||
book: "kb",
|
||||
volume: seg.volume ?? 1,
|
||||
chapter: seg.chapter ?? null,
|
||||
title: seg.title,
|
||||
type: seg.type || "intro-segment",
|
||||
slug: seg.slug || file.replace(".json", ""),
|
||||
order: seg.order ?? 0,
|
||||
paragraphs: seg.paragraphs,
|
||||
});
|
||||
}
|
||||
await insertBatched(proseCol, introDocsV1);
|
||||
console.log(` Vol 1 intro segments: ${introFiles.length}`);
|
||||
}
|
||||
|
||||
// Volume 1 chapters
|
||||
const vol1ChapDir = path.join(LIB_DIR, "books", "kb", "vol-1", "chapters");
|
||||
if (fs.existsSync(vol1ChapDir)) {
|
||||
const chapterFiles = fs
|
||||
.readdirSync(vol1ChapDir)
|
||||
.filter((f) => f.endsWith(".json"))
|
||||
.sort();
|
||||
|
||||
const chapDocsV1: Record<string, unknown>[] = [];
|
||||
for (const file of chapterFiles) {
|
||||
const ch = readJson<ProseChapterJson>(path.join(vol1ChapDir, file));
|
||||
chapDocsV1.push({
|
||||
book: "kb",
|
||||
volume: ch.volume ?? 1,
|
||||
chapter: ch.chapter ?? null,
|
||||
title: ch.title,
|
||||
type: ch.type || "chapter",
|
||||
slug: String(ch.chapter ?? file.replace(".json", "")).padStart(2, "0"),
|
||||
order: 100 + (ch.chapter ?? 0),
|
||||
paragraphs: ch.paragraphs,
|
||||
});
|
||||
}
|
||||
await insertBatched(proseCol, chapDocsV1);
|
||||
console.log(` Vol 1 chapters: ${chapterFiles.length}`);
|
||||
}
|
||||
|
||||
// Volume 2 intro segments
|
||||
const vol2IntroDir = path.join(LIB_DIR, "books", "kb", "vol-2", "intro");
|
||||
if (fs.existsSync(vol2IntroDir)) {
|
||||
const introFiles = fs
|
||||
.readdirSync(vol2IntroDir)
|
||||
.filter((f) => f.endsWith(".json"))
|
||||
.sort();
|
||||
|
||||
const introDocsV2: Record<string, unknown>[] = [];
|
||||
for (const file of introFiles) {
|
||||
const seg = readJson<ProseChapterJson>(path.join(vol2IntroDir, file));
|
||||
introDocsV2.push({
|
||||
book: "kb",
|
||||
volume: seg.volume ?? 2,
|
||||
chapter: seg.chapter ?? null,
|
||||
title: seg.title,
|
||||
type: seg.type || "intro-segment",
|
||||
slug: seg.slug || file.replace(".json", ""),
|
||||
order: seg.order ?? 0,
|
||||
paragraphs: seg.paragraphs,
|
||||
});
|
||||
}
|
||||
await insertBatched(proseCol, introDocsV2);
|
||||
console.log(` Vol 2 intro segments: ${introFiles.length}`);
|
||||
}
|
||||
|
||||
// Volume 2 chapters
|
||||
const vol2ChapDir = path.join(LIB_DIR, "books", "kb", "vol-2", "chapters");
|
||||
if (fs.existsSync(vol2ChapDir)) {
|
||||
const chapterFiles = fs
|
||||
.readdirSync(vol2ChapDir)
|
||||
.filter((f) => f.endsWith(".json"))
|
||||
.sort();
|
||||
|
||||
const chapDocsV2: Record<string, unknown>[] = [];
|
||||
for (const file of chapterFiles) {
|
||||
const ch = readJson<ProseChapterJson>(path.join(vol2ChapDir, file));
|
||||
chapDocsV2.push({
|
||||
book: "kb",
|
||||
volume: ch.volume ?? 2,
|
||||
chapter: ch.chapter ?? null,
|
||||
title: ch.title,
|
||||
type: ch.type || "chapter",
|
||||
slug: String(ch.chapter ?? file.replace(".json", "")).padStart(2, "0"),
|
||||
order: 100 + (ch.chapter ?? 0),
|
||||
paragraphs: ch.paragraphs,
|
||||
});
|
||||
}
|
||||
await insertBatched(proseCol, chapDocsV2);
|
||||
console.log(` Vol 2 chapters: ${chapterFiles.length}`);
|
||||
}
|
||||
|
||||
const totalDocs = await proseCol.countDocuments({ book: "kb" });
|
||||
console.log(` ✅ KB: ${totalDocs} prose entries`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Glossary
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -419,16 +575,14 @@ async function seedGlossary(db: ReturnType<MongoClient["db"]>) {
|
||||
const col = db.collection("glossary");
|
||||
await col.deleteMany({});
|
||||
|
||||
const docs = data.entries.map((entry) => ({
|
||||
const glossaryDocs = data.entries.map((entry) => ({
|
||||
term: entry.term,
|
||||
definition: entry.definition,
|
||||
definitionHtml: entry.definition_html,
|
||||
}));
|
||||
|
||||
if (docs.length > 0) {
|
||||
await col.insertMany(docs, { ordered: false });
|
||||
}
|
||||
console.log(` ✅ Glossary: ${docs.length} entries`);
|
||||
await insertBatched(col, glossaryDocs);
|
||||
console.log(` ✅ Glossary: ${glossaryDocs.length} entries`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -453,6 +607,12 @@ async function createIndexes(db: ReturnType<MongoClient["db"]>) {
|
||||
const glossaryCol = db.collection("glossary");
|
||||
await glossaryCol.createIndex({ term: 1 }, { unique: true });
|
||||
|
||||
const proseCol = db.collection("prose_chapters");
|
||||
await proseCol.createIndex({ book: 1 });
|
||||
await proseCol.createIndex({ book: 1, volume: 1 });
|
||||
await proseCol.createIndex({ book: 1, volume: 1, slug: 1 }, { unique: true });
|
||||
await proseCol.createIndex({ book: 1, volume: 1, type: 1 });
|
||||
|
||||
console.log(" ✅ Indexes created");
|
||||
}
|
||||
|
||||
@@ -487,11 +647,15 @@ async function main() {
|
||||
await seedSb1962(db);
|
||||
console.log();
|
||||
|
||||
console.log("[5/6] Glossary");
|
||||
console.log("[5/7] Kṛṣṇa Book");
|
||||
await seedKb(db);
|
||||
console.log();
|
||||
|
||||
console.log("[6/7] Glossary");
|
||||
await seedGlossary(db);
|
||||
console.log();
|
||||
|
||||
console.log("[6/6] Indexes");
|
||||
console.log("[7/7] Indexes");
|
||||
await createIndexes(db);
|
||||
console.log();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user