O‘zbekcha · English
Google Sheets uchun tipli (type-safe), server tomonda ishlovchi qidiruv qatlami — varaqni xuddi kichik ORM kabi modellashtiring.
sheetq Google jadvalini kichik, tipli ma'lumotlar ombariga aylantiradi. Siz varaq
ustunlarini bir marta tavsiflaysiz va to'liq tipli model olasiz: find / insert /
update / delete — qo'lda interfeys yozish ham, A1 diapazonlarini hisoblash ham
shart emas.
Qidiruvlar server tomonda, Google Visualization API (gviz) orqali ishlaydi:
10 000 ta qatorni tortib olib JS'da filter qilish O'RNIGA, sheetq Google serveriga
SQL'simon so'rov yuboradi va faqat mos qatorlarni qaytaradi. 10 000 qator ichidan
bittasini topish = bitta so'rov.
const Users = spreadsheet
.doc("<spreadsheetId>") // jadval URL'idagi uzun id
.model("users", {
columns: {
id: { col: "B", type: "number" },
name: { col: "C", type: "string" },
email: { col: "D", type: "string" },
},
});
const user = await Users.findOne({ id: 5042 }, { exact: true });
// ^? { id: number | null; name: string | null; email: string | null } | null- Sxemadan tip chiqarish — qator tipi
columnsdan AVTOMATIK olinadi; alohida interfeys yozmaysiz. - Server tomonda qidiruv —
find/findOnegvizso'roviga aylanadi, faqat mos qatorlar qaytadi. - O'qish va yozish —
insert,insertMany,update,delete,set,clear,clearRange, hamda formulani avtomatik to'ldirish. - Ustun bo'yicha konvertatsiya —
string/number/boolean/date[:FORMAT], yoki o'zingizningtransform(o'qish) vaserialize(yozish) funksiyalaringiz. - Harf bo'yicha ustunlar — fieldlarni haqiqiy ustun harflariga bog'laysiz (
"A","B","F"…); ustunlar orasida bo'shliq bo'lsa ham ishlaydi. - Yengil — faqat
googleapisvadayjsga bog'liq.
yarn add sheetq
# kerakli paketlar avtomatik o'rnatiladi: googleapis, dayjssheetq faqat backend uchun (Node.js ≥ 24). U Google service account bilan
autentifikatsiya qiladi va browserda chaqirilsa xato beradi.
- Google Cloud Console da service account yarating va uning JSON kalitini yuklab oling.
- Loyiha uchun Google Sheets API ni yoqing.
- Jadvalni service account email'i (
...@...gserviceaccount.com) bilan ulashing — faqat o'qish uchun "Viewer", yozish uchun "Editor".
import Spreadsheet from "sheetq";
import cred from "./service-account.json" assert { type: "json" };
// To'liq credentials JSON obyektini berasiz:
const spreadsheet = new Spreadsheet(cred); // o'qish + yozish
// Faqat o'qish rejimi (readonly scope so'raydi):
const ro = new Spreadsheet(cred, { readonly: true });
// Yoki email + key'ni to'g'ridan-to'g'ri (mas. env'dan):
const ss = new Spreadsheet(
process.env.GOOGLE_CLIENT_EMAIL!,
process.env.GOOGLE_PRIVATE_KEY!, // `\n` belgilar avtomatik to'g'rilanadi
);Bitta Spreadsheet klienti ko'plab hujjatlarga xizmat qila oladi — auth va Sheets
klienti lazy (kerak bo'lganda) quriladi va keshlanadi.
const doc = spreadsheet.doc("<spreadsheetId>"); // jadval URL'idagi uzun id
const Users = doc.model("users", { // "users" = varaq (tab) nomi
columns: {
id: { col: "B", type: "number" },
name: { col: "C", type: "string" },
email: { col: "D", type: "string" },
role: { col: "F", type: "string" },
},
startRow: 2, // ma'lumot boshlanadigan qator (header'dan keyin). Default: 2
});interface ColumnDef {
col: string; // "A", "B", "C"... (ustun harfi)
type?: "string" | "number" | "boolean" | "date" | `date:${string}`;
transform?: (raw: Cell) => unknown; // O'QISHda: xom katak → istalgan qiymat
serialize?: (value: any) => Cell; // YOZISHda: boy qiymat → katak qiymati
}type |
O'qishda qaytadi | Yozishda qabul qiladi |
|---|---|---|
"string" |
string | null |
string |
"number" |
number | null |
number |
"boolean" |
boolean | null |
boolean |
"date" |
Date | null |
Date |
"date:DD.MM.YYYY" |
Date | null |
formatlangan matn |
"date" — ISO sanani parse/format qiladi. Agar sana varaqda matn ko'rinishida
saqlansa, "date:FORMAT" ishlating (FORMAT — dayjs formati),
masalan: "date:DD.MM.YYYY HH:mm:ss".
Tayyor type yetarli bo'lmaganda, o'z funksiyalaringizni berasiz. Eng muhimi —
ular ikki xil yo'nalishda ishlaydi:
transform— O'QISHda ishlaydi: varaqdan kelgan xom katakni (raw) istalgan qiymatga aylantiradi. Field'ning TS tipi aynan shu funksiyaningreturntipidan olinadi.serialize— YOZISHda ishlaydi: sizning boy qiymatingizni varaqqa yoziladigan oddiy qiymatga (matn/son/boolean) aylantiradi.
Aynan siz belgilab ko'rsatgan misol:
import { getFormattedDate } from "utilzify";
const usersModel = taklifnomaDoc.model("users", {
columns: {
timestamp: {
col: "A",
type: "string",
transform: raw => new Date(raw as string), // O'QISH: "2026-06-22 14:30" → Date obyekti
serialize: raw => getFormattedDate(raw), // YOZISH: Date → "22.06.2026 14:30" matni
},
id: { col: "B", type: "number" },
name: { col: "C", type: "string" },
email: { col: "D", type: "string" },
role: { col: "F", type: "string" },
},
startRow: 2,
});Bu nima qiladi:
transform: raw => new Date(raw as string)— varaqdagi katakda sana matn ko'rinishida turadi. O'qiyotgandasheetqxom matnni oladi va uni JSDateobyektiga aylantiradi. Shuning uchunusers[i].timestamp— bu haqiqiyDate, matn emas.serialize: raw => getFormattedDate(raw)— yozayotganda (insert/update/set) sizDate(yoki boshqa qiymat) berasiz, lekin varaqqa chiroyli, formatlangan matn yozilishi kerak.getFormattedDateaynan shuni qiladi.
getFormattedDate— shunchaki misol formatlovchi funksiya (utilzifypaketidan). O'rniga istalgan funksiya ishlatsa bo'ladi, masalandayjs(raw).format("DD.MM.YYYY"). Yoki butuntransform/serializeo'rniga shunchakitype: "date:DD.MM.YYYY HH:mm:ss"berib, xuddi shu natijaga erishish mumkin.
Ustunni ikki xil yozish mumkin — natija (tip ham, xulq ham) bir xil. Ikkalasini bitta modelda aralashtirib ham ishlatsa bo'ladi.
1-usul — obyekt literali (to'liq moslashuvchan):
doc.model("users", {
columns: {
id: { col: "B", type: "number" },
name: { col: "C", type: "string" },
active: { col: "E", type: "boolean" },
bornAt: { col: "F", type: "date:DD.MM.YYYY" },
},
});2-usul — columns builder (qisqaroq):
import { columns as c } from "sheetq";
doc.model("users", {
columns: {
id: c.number("B"),
name: c.string("C"),
active: c.boolean("E"),
bornAt: c.date("F", "DD.MM.YYYY"),
},
});Builder'lar literal tipni saqlaydi, shuning uchun row tipi aynan bir xil chiqadi (
id: number | null,bornAt: Date | null, ...). Hech qanday tip yo'qotilmaydi.
Har bir builder:
| Builder | Teng obyekt literali | Field tipi (o'qishda) |
|---|---|---|
c.string("C") |
{ col: "C", type: "string" } |
string | null |
c.number("B") |
{ col: "B", type: "number" } |
number | null |
c.boolean("E") |
{ col: "E", type: "boolean" } |
boolean | null |
c.date("F") |
{ col: "F", type: "date" } |
Date | null (ISO) |
c.date("F", "DD.MM.YYYY") |
{ col: "F", type: "date:DD.MM.YYYY" } |
Date | null (matn) |
c.parsed("G", parse, serialize?) |
{ col: "G", transform: parse, serialize } |
parse return tipi |
c.string(col)— matn ustuni. O'qishdaString(...), yozishda matn.c.number(col)— son ustuni. O'qishdaNumber(...)(parse bo'lmasanull), yozishda son.c.boolean(col)— mantiqiy ustun."TRUE"/"true"/true→true, aks holdafalse.c.date(col)— ISO sana.c.date(col, "FORMAT")— sana matn ko'rinishida saqlangan bo'lsa, dayjs formati bilan (mas."DD.MM.YYYY HH:mm:ss").
c.parsed — bu obyekt literalidagi transform (va ixtiyoriy serialize)ning qisqa
yozuvi. Tayyor tiplar (string/number/date...) yetmaganda ishlatiladi.
c.parsed(col, parse, serialize?)parse: (raw) => R— O'QISHda ishlaydi: varaqdan kelgan xom katakni (raw) siz xohlagan qiymatga aylantiradi. Field'ning tipi (R) aynan shu funksiyaning return'idan olinadi. Masalanr => new Date(...)bo'lsa, field tipiDatebo'ladi.serialize?: (value: R) => Cell— YOZISHda ishlaydi (ixtiyoriy): sizning boy qiymatingizni (R) varaqqa yoziladigan oddiy qiymatga (matn/son/boolean) aylantiradi. Bermasangiz — faqat o'qish uchun mo'ljallangan bo'ladi.
import dayjs from "dayjs";
// Faqat o'qish: xom matn → Date
joinedAt: c.parsed("G", r => new Date(r as string)),
// O'qish + yozish: Date → "22.06.2026" matni
bornAt: c.parsed(
"F",
r => new Date(r as string), // O'QISH: "22.06.2026" → Date
d => dayjs(d).format("DD.MM.YYYY"), // YOZISH: Date → "22.06.2026"
),Bu quyidagi obyekt literaliga to'liq teng:
bornAt: {
col: "F",
transform: r => new Date(r as string),
serialize: d => dayjs(d).format("DD.MM.YYYY"),
},Qachon qaysi biri? Oddiy tipli ustunlar uchun builder qisqaroq va tozaroq;
transform/serializemantiqi murakkab bo'lsa yoki bir nechta parametr kerak bo'lsa, obyekt literali ko'proq nazorat beradi. Ikkalasini bir modelda aralashtirsangiz ham bo'ladi.
import type { InferModel } from "sheetq";
type User = InferModel<typeof Users>;
// { timestamp: Date; id: number | null; name: string | null; ... }// Hamma qator (butun sheet, obyektlarga parse qilingan)
const all = await Users.all();
// Default — "yumshoq" qidiruv: matn ustunlarida registrga befarq qism-matn
const alis = await Users.find({ name: "ali" }); // "Ali", "Alisher" ham topadi
// Aniq tenglik
const u = await Users.findOne({ id: 5042 }, { exact: true });
// Qo'shimcha parametrlar: limit / orderBy / dir / exact
const top = await Users.find(
{ role: "admin" },
{ orderBy: "id", dir: "desc", limit: 10, exact: true },
);Qidiruv qoidalari
- Default (
exact: false): matn (string) fieldlar registrga befarqcontainsbilan, qolganlari=bilan solishtiriladi. Foydalanuvchi qidiruv maydonchasi uchun qulay. exact: true: hamma field aniq tenglik (=) bilan tekshiriladi.- match obyektidagi bir nechta field
ANDbilan birlashtiriladi. null— bo'sh kataklarga mos keladi (is null).
// Xom o'qish — sxemada YO'Q ustunlarni HAM oladi; Cell[][] qaytaradi (parse qilmaydi)
const grid = await Users.allRaw(); // butun sheet
const slice = await Users.allRaw({ fromRow: 2, limit: 100 });
// Header qatorlari (startRow'dan yuqoridagilar), xom ko'rinishda
const headerRows = await Users.headers(); // string[][]
// Har bir field uchun header qiymatlari
const map = await Users.headerMap();
// → { id: ["ID"], name: ["Ism"], ... }Yozish uchun o'qish-yozish scope kerak (
{ readonly: true }BERMANG) va service account jadvalga Editor huquqiga ega bo'lishi shart.
// Oxiriga bitta / bir nechta qator qo'shish
await Users.insert({ id: 1, name: "Ali", email: "ali@example.com" });
await Users.insertMany([
{ id: 2, name: "Vali" },
{ id: 3, name: "Guli" },
]);
// Mos qatorlarni patch bilan yangilash — nechta qator o'zgargani qaytadi
const changed = await Users.update({ id: 5042 }, { name: "Vali" }, { exact: true });
// Mos qatorlarni o'chirish (qatorlar olib tashlanadi) — nechta o'chirilgani qaytadi
const removed = await Users.delete({ role: "guest" });
// Qiymatlarni belgilangan qatordan boshlab USTIGA yozish (yangi qator QO'SHMAYDI)
await Users.set([{ id: 1, name: "Ali" }, { id: 2, name: "Vali" }]); // startRow'dan
await Users.set(rows, { fromRow: 10 }); // 10-qatordan
// Mos qatorlarning kataklarini bo'shatish (qator JOYIDA qoladi) — soni qaytadi
await Users.clear({ id: 5042 }, { exact: true });
await Users.clear({}); // hamma ma'lumot qatorini bo'shatadi
// Pozitsiya (diapazon) bo'yicha tozalash — match'siz
await Users.clearRange(); // hamma ma'lumot
await Users.clearRange({ fromRow: 5, toRow: 20 });
await Users.clearRange({ fromCol: "B", toCol: "D" });
// Formulani pastga "tortish" (autoFill) — nisbiy ssilkalarni har qatorga moslaydi.
// Manba katakda formula bo'lmasa — hech narsa qilmaydi (false qaytaradi).
await Users.fillFormula({ col: "E", fromRow: 2, toRow: 5000 });update / delete / clear xuddi find kabi match parametrlarini qabul qiladi
(exact, limit).
Har bir amal o'ralgan — xato SpreadsheetError ko'rinishida, qaysi metod va qaysi
varaqda yuz bergani konteksti bilan chiqadi.
import { SpreadsheetError } from "sheetq";
try {
await Users.insert({ id: 1 });
} catch (err) {
if (err instanceof SpreadsheetError) {
console.error(err.message); // "sheetq.insert (sheet: users): ..."
console.error(err.context); // { method: "insert", sheet: "users", ... }
}
}credentials— service-account JSON ({ client_email, private_key, ... }).options.readonly— readonly scope so'raydi (default: o'qish + yozish).options.scopes— maxsus scope'lar (readonly'dan ustun turadi)..doc(spreadsheetId)→Document
.model(sheetName, config)→Model—configbu{ columns, startRow? }.
| Metod | Qaytaradi | Tavsif |
|---|---|---|
find(match?, options?) |
T[] |
Mos qatorlar (server tomonda gviz). |
findOne(match?, options?) |
T | null |
Birinchi mos qator. |
all(options?) |
T[] |
Hamma qator. |
allRaw(options?) |
Cell[][] |
Xom jadval, sxemada yo'q ustunlar bilan. |
headers() |
string[][] |
Xom header qatorlari (startRow'dan yuqori). |
headerMap() |
Record<field,string[]> |
Field bo'yicha header qiymatlari. |
insert(obj) |
void |
Bitta qator qo'shadi (oxiriga). |
insertMany(objs) |
void |
Ko'p qatorni bitta so'rovda qo'shadi. |
update(match, patch, options?) |
number |
Mos qatorlarni yangilaydi; soni qaytadi. |
delete(match, options?) |
number |
Mos qatorlarni o'chiradi; soni qaytadi. |
set(rows, options?) |
void |
Qatordan boshlab ustiga yozadi (qo'shmaydi). |
clear(match, options?) |
number |
Mos qatorlar kataklarini bo'shatadi; soni. |
clearRange(options?) |
void |
Qator/ustun diapazonini bo'shatadi. |
fillFormula({ col, fromRow, toRow }) |
boolean |
Formulani pastga to'ldiradi; yo'q bo'lsa false. |
col(field) |
string |
Field uchun ustun harfi. |
range(endRow?) |
string |
Sxema uchun A1 diapazoni (mas. users!B2:F). |
parse(row) / serialize(obj) |
T / Cell[] |
Qo'lda qator ↔ obyekt konvertatsiyasi. |
Parametrlar (Options)
FindOptions—{ limit?, orderBy?, dir?: "asc" | "desc", exact? }MatchOptions—{ exact?, limit? }SetOptions—{ fromRow? }RawOptions—{ fromRow?, toRow?, limit? }ClearOptions—{ fromRow?, toRow?, fromCol?, toCol? }
yarn install
yarn typecheck # tsc --noEmit
yarn build # tsup → dist/ (ESM + CJS + .d.ts)MIT © Suhrobbek Soatov