
Günümüzün veri odaklı dünyasında, ölçeklenebilir, yüksek performanslı ve yüksek erişilebilirlik sunan veritabanlarına duyulan ihtiyaç hiç olmadığı kadar büyük. AWS (Amazon Web Services) tarafından sunulan, tamamen yönetilen, sunucusuz, geniş sütunlu anahtar-değer deposu Amazon DynamoDB bu gereksinimleri karşılamak üzere tasarlanmıştır. İster bir web uygulaması, ister mobil uygulama ya da esnek ve güvenilir depolama gerektiren herhangi bir sistem geliştiriyor olun, DynamoDB size gereken desteği sağlar.
Bu eğitim, sizi Amazon DynamoDB dünyasıyla tanıştırmayı ve Node.js uygulamalarında onu etkili bir şekilde nasıl kullanacağınızı göstermeyi amaçlar. NoSQL veritabanlarına yeni başlayan biri olun ya da beceri yelpazenizi genişletmek isteyen deneyimli bir geliştirici, bu rehber temel konuları adım adım açıklayacak ve başlamanıza yardımcı olacak pratik örnekler sunacaktır.
DynamoDB nedir?
Amazon DynamoDB, kesintisiz ölçeklenebilirlik ve düşük gecikme performansı sunan, sunucusuz bir anahtar-değer ve belge veritabanıdır. Geleneksel ilişkisel veritabanlarının aksine, DynamoDB donanım temini yapmanızı veya altyapıyı yönetmenizi gerektirmez; bu da iş yüklerindeki değişimlere dinamik olarak yanıt veren uygulamalar için ideal bir seçim olmasını sağlar.
DynamoDB'nin başlıca özellikleri şunlardır:
Ölçeklenebilirlik
DynamoDB saniyede milyonlarca isteği işleyebilir; bu da farklı trafik seviyelerine sahip uygulamalar için uygundur.
Yüksek erişilebilirlik
Birden çok erişilebilirlik bölgesine yerleşik çoğaltma ile yüksek erişilebilirlik ve veri dayanıklılığı için tasarlanmıştır.
Yönetilen hizmet
AWS, donanım temini, yamalama ve yedeklemeler dahil işletimsel yükü üstlenir; böylece siz uygulamanızı geliştirmeye odaklanabilirsiniz.
Esnek veri modeli
DynamoDB hem anahtar-değer hem de belge veri modellerini destekler; bu da verinizi yapılandırırken esneklik sağlar.
Güvenlik
AWS Identity and Access Management (IAM) entegrasyonu, öğe ve öznitelik düzeyinde veritabanı kaynaklarınıza ayrıntılı güvenli erişim kontrolü sağlar.
Maliyet tasarrufu
DynamoDB'nin sunucusuz mimarisi ve otomatik ölçeklendirme yetenekleri, yalnızca tükettiğiniz kaynaklar için ödeme yaparak maliyetleri optimize etmenizi sağlar. Peşin donanım maliyeti veya uzun vadeli taahhütler yoktur; bu da hem girişimler hem de kurumsal şirketler için uygun maliyetli bir seçim yapar.
Veri türleri
DynamoDB'de desteklenen veri türleri:
- Skaler türler: Metinler (string), sayılar, ikililer (binary), boolean'lar ve null değerler.
- Belge türleri: DynamoDB, iç içe özniteliklere sahip karmaşık yapıları destekler; bu da JSON verileri için idealdir.
- Küme (set) türleri: Metin kümeleri, sayı kümeleri ve ikili kümeler, ilişkili değer koleksiyonlarını verimli şekilde saklamanızı sağlar.
Neden DynamoDB'yi Node.js ile kullanmalı?
Node.js, web sunucuları ve API'ler dahil sunucu tarafı uygulamalar geliştirmek için popüler bir çalışma zamanıdır. Engellemesiz, olay güdümlü mimarisi, DynamoDB'nin eşzamansız API'siyle iyi eşleşir ve Node.js geliştiricileri için doğal bir tercih olur.
Bu eğitimde aşağıdaki konuları ele alacağız:
1. DynamoDB'de tablolar oluşturma ve şema tanımlama.
2. AWS SDK for Node.js kullanarak temel CRUD (Create, Read, Update, Delete) işlemleri.
3. ACID uyumluluğuyla gelişmiş sorgulama.
Bu eğitimin sonunda Amazon DynamoDB'yi sağlam bir şekilde anlamış olacak ve onun gücünden Node.js uygulamalarınızda nasıl yararlanacağınızı bileceksiniz. Hadi başlayalım ve bu çok yönlü NoSQL veritabanının potansiyelini açığa çıkaralım!
Hazırlık
Başlamadan önce bir AWS hesabına ihtiyacınız olacak. Bunu AWS hesabı olmadan da yapabilirdik; ancak daha gerçekçi bir örnek için altyapımızı AWS'de oluşturmak amacıyla terraform kullanacağız. Docker kullanarak yerelde AWS servisleriyle nasıl çalışılacağına dair daha fazla bilgi için, başvurup deneyebileceğiniz bir örnek demo localstack github deposu hazırladım.
Eğer yüklü değilse şimdi terraform kurma zamanı.
Bu eğitimin geri kalanında, AWS CLI'ı kimlik bilgileri ve yapılandırma dosyalarınızla kurduğunuzu ve terraform'un yüklü olduğunu varsayacağız.
Başlarken
Bu eğitimde typescript ve yarn kullanacağız. Basit başlamak için ts-node kullanacağız; bir sonraki eğitimde ise sunucusuz (serverless) yaklaşıma geçerek bunu AWS Lambda ile genişleteceğiz.
Demo projemizi kurmak için yeni bir klasör oluşturun ve ardından aşağıdaki bağımlılıkları ekleyip kurulumu çalıştırın:
yarn init
yarn add --dev typescript ts-node @types/node @types/ramda @types/uuid
yarn add @aws-sdk/client-dynamodb ramda uuid
npx tsc --init
mkdir src src/domain infra
touch ./src/index.ts ./src/client.ts ./infra/main.tf ./src/domain/student.ts
Sonraki adımda package.json'a aşağıdaki scripts bölümünü ekleyin
"scripts": {
"dev": "ts-node src/index.ts"
},
main.tf
provider "aws" {
region = "eu-west-1"
}
resource "aws_dynamodb_table" "demo-table" {
name = "demo-table"
billing_mode = "PAY_PER_REQUEST"
hash_key = "pk"
range_key = "sk"
attribute {
name = "pk"
type = "S"
}
attribute {
name = "sk"
type = "S"
}
}
Komut satırından infra dizinine gidin ve terraform init && terraform apply -auto-approve komutunu çalıştırın; ardından AWS konsoluna gidip DynamoDB tablonuzu görüntüleyin:

DynamoDB faturalandırma modlarını, WCU'ları ve RCU'ları ayrı bir yazıda ele alacağım
client.ts
import { DynamoDB } from "@aws-sdk/client-dynamodb";
export const TABLE_NAME = "demo-table";
export const REGION = "eu-west-1";
export const dynamoClient = new DynamoDB({ region: REGION });
export const STUDENT_PREFIX = "student#";
Veri Modeli
Daha ileri gitmeden önce, bu eğitimin kapsamı için kullanabileceğimiz bir veri modeli tanımlayalım. Bağlamı korumak için, DataCamp'in temel özelliklerine yakın bir şeyi modellemeyi seçtim.
Bu eğitim tüm varlıkları kapsamayacak. Bu modeli sonraki yazılarda genişleteceğim.

DynamoDB ile CRUD İşlemleri
DynamoDB ile veri tasarlama ve modellemenin tamamını anlamak için DynamoDB ile tek tablo tasarımı eğitimime bakın. Bu eğitimde, DynamoDB'nin nasıl çalıştığına dair açıklamayı minimumda tutmaya çalışacağım. Hatırlanması gereken temel nokta, DynamoDB'nin verimli veri yönetimi için bölüm (partition) anahtarları ve sıralama (sort) anahtarları kullandığıdır.
Bölüm anahtarları
Bölüm anahtarları, veriyi birden çok depolama sunucusuna dağıtmak için kullanılır. Verinizi eşit şekilde dağıtan bir bölüm anahtarı seçmek önemlidir; aksi halde performans sorunlarına yol açabilecek "sıcak bölümler" (eşit olmayan veri dağılımı) oluşabilir.
Veriyi eşit dağıtmaya yardımcı olan bölüm anahtarı seçimlerine örnek olarak yüksek ayırt ediciliğe (kardinaliteye) sahip öznitelikler verilebilir:
- benzersiz kimlikler (ID'ler)
- kullanıcı kimlikleri
- karma (hash) değerleri
- coğrafi bölgeler
- zaman tabanlı anahtarlar
- bileşik anahtarlar
Bölüm anahtarı seçimi, büyük ölçüde uygulamanın erişim desenlerine ve veri modeline bağlıdır.
Sıralama anahtarları
Sıralama anahtarları isteğe bağlıdır ve bir bölüm içinde veriyi düzenlemenizi sağlar. Bir bölüm içinde verimli sorgulama ve sıralama için sıralama anahtarlarını kullanın.
Bileşik anahtarlar
Bileşik anahtarlar hem bölüm hem de sıralama anahtarlarından oluşur. Aralık, zaman veya diğer özniteliklere göre filtreleme gibi zengin sorgu desenleri oluşturmanıza olanak tanır. Veri erişim desenlerinizin karmaşık sorgular gerektirdiği durumlarda bileşik anahtarlar kullanın.
Sıcak bölümler
Sıcak bölümleri azaltmak için, bölüm anahtarları için rastgele önekler kullanarak sharding, zaman tabanlı bölümleme veya yazmaları eşit dağıtma gibi stratejileri düşünün. İzleme yapın ve kapasiteyi dinamik olarak ayarlamak için AWS Auto Scaling kullanın.
student.ts
İşleri basit tutmak için öğrenci kimliğini hem bölüm anahtarı hem de sıralama anahtarı olarak kullanacağız. Bu garip bir seçim gibi görünebilir; ancak şemamızı esnek tutmamız ve çeşitli veri ilişkilerini ve erişim desenlerini desteklemeye hazır olmamız gerekiyor. Bu modeli sonraki DynamoDB yazılarında genişleteceğim.
import { head, omit, pathOr } from "ramda";
import { STUDENT_PREFIX, TABLE_NAME, dynamoClient as client } from "../client";
import { v4 as uuidv4 } from "uuid";
import {
addPrefix,
attributeMapToValues,
attributeValueToValue,
removePrefix,
valueToAttributeValue,
} from "../utils";
const entityType = "student";
export const dynamoRecordToStudent = (record: any) => {
const { pk, ...data } = record;
return omit(["sk"], {
...attributeMapToValues(data),
id: removePrefix(attributeValueToValue<string>(pk), STUDENT_PREFIX),
});
};
export const getStudentById = (id: string) =>
client
.getItem({
TableName: TABLE_NAME,
Key: {
pk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
sk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
},
})
.then(({ Item }) => (Item ? dynamoRecordToStudent(Item) : undefined));
export const saveStudent = async ({
firstName,
lastName,
email,
}: {
firstName: string;
lastName: string;
email: string;
}): Promise<string> => {
const _id = uuidv4();
const _email = email.toLocaleLowerCase();
const xp = 0;
await client.putItem({
TableName: TABLE_NAME,
Item: {
pk: valueToAttributeValue(addPrefix(_id, STUDENT_PREFIX)),
sk: valueToAttributeValue(addPrefix(_id, STUDENT_PREFIX)),
firstName: valueToAttributeValue(firstName),
lastName: valueToAttributeValue(lastName),
email: valueToAttributeValue(_email),
xp: valueToAttributeValue(xp),
entityType: valueToAttributeValue(entityType),
},
});
return _id;
};
utils.ts
AWS'in en yeni DynamoDB SDK'sı, veritabanında saklanan öğeler için tip güvenliğini artırdı; ancak bunu yaparken kullanımını biraz zorlaştırdı. Bu zorluğu hafifletmek için bazı yardımcı işlevler oluşturalım. DynamoDB'nin veriyi dahili olarak nasıl sakladığını gördüğümüzde neden onlara ihtiyaç duyduğumuz daha net olacak.
utils.ts adlı yeni bir dosyayı src klasörünün köküne oluşturun.
import { AttributeValue } from "@aws-sdk/client-dynamodb";
export const valueToAttributeValue = <T>(value: T): AttributeValue => {
switch (typeof value) {
case "string":
return { S: value };
case "number":
return { N: `${value}` };
case "boolean":
return { BOOL: value };
case "object":
if (Array.isArray(value)) {
return { L: value.map((item) => valueToAttributeValue(item)) };
}
return {
M: Object.entries(value as any).reduce(
(acc, [key, item]) => ({
...acc,
[key]: valueToAttributeValue(item),
}),
{}
),
};
default:
throw new Error(`Unknown type ${typeof value}`);
}
};
export const attributeValueToValue = <T>(value: AttributeValue): T => {
switch (true) {
case !!value.S:
return value.S as T;
case !!value.N:
return Number(value.N) as T;
case !!value.BOOL:
return value.BOOL as T;
case !!value.L:
return value.L?.map((item) =>
attributeValueToValue(item)
) as unknown as T;
case !!value.M:
return Object.entries(value.M || []).reduce(
(acc, [key, item]) => ({ ...acc, [key]: attributeValueToValue(item) }),
{}
) as unknown as T;
default:
throw new Error(`Unknown type ${JSON.stringify(value)}`);
}
};
export const attributeMapToValues = (
items: Record<string, AttributeValue>
): unknown[] =>
Object.keys(items).reduce(
(acc, key) => ({
...acc,
[key]: attributeValueToValue(items[key]),
}),
[]
);
export const removePrefix = (id: string, prefix: string): string =>
id.replace(prefix, "");
export const addPrefix = (id: string, prefix: string): string =>
`${prefix}${removePrefix(id, prefix)}`;
Yeni bir öğrenci oluşturma
Nihayet artık DynamoDB'ye CRUD işlem API çağrıları göndermeye hazırız!
index.ts dosyasını açın ve aşağıdaki kodu yapıştırın; ardından komut satırından yarn dev çalıştırın.
import { getStudentById, saveStudent } from "./domain/student";
Promise.resolve()
.then(async () => {
const id = await saveStudent({
firstName: "John",
lastName: "Smith",
email: "john@datacamp.com",
});
const john = await getStudentById(id);
console.log(john);
})
.catch((err) => {
console.error(err);
process.exit(1);
})
.then(() => {
console.log("done");
process.exit(0);
});
Şuna benzer bir çıktı görmelisiniz:
{
"entityType": "student",
"id": "dd4c2ee4-9422-4957-ae6f-f9fff748e5ab",
"firstName": "John",
"lastName": "Smith",
"email": "john@datacamp.com",
"xp": 0
}
Şimdi CLI kullanarak aşağıdaki komutla DynamoDB'yi tarayın:
aws dynamodb scan --table-name demo-table --no-cli-pager
Çıktıdan, DynamoDB'nin veriyi dahili olarak nasıl sakladığını ve türlediğini görebilirsiniz; burada N sayı türünü, S ise metin türünü ifade eder ve utils.ts dosyasındaki kodla ilgili aklınıza takılmış olabilecek soruları netleştirmelidir.
{
"Items": [
{
"entityType": {
"S": "student"
},
"lastName": {
"S": "Smith"
},
"email": {
"S": "john@datacamp.com"
},
"xp": {
"N": "0"
},
"sk": {
"S": "student#dd4c2ee4-9422-4957-ae6f-f9fff748e5ab"
},
"pk": {
"S": "student#dd4c2ee4-9422-4957-ae6f-f9fff748e5ab"
},
"firstName": {
"S": "John"
}
}
],
"Count": 1,
"ScannedCount": 1,
"ConsumedCapacity": null
}
E-posta adresiyle öğrenci getirme
Kayıt bulmak için elimizde yalnızca öğrencinin e-posta adresi olsaydı ne yapardık? Bu erişim desenini bir küresel ikincil indeks ekleyerek destekleyebiliriz.
Önce, orijinal tablomuzu yok etmemiz gerekiyor (gelecekteki terraform değişiklikleri için bu adımı, bir tablo boşaltma işlevi ekleyerek aşacağız):
terraform destroy
Ardından terraform'u güncelleyip demo-table'ımıza aşağıdaki GSI'ı ekleyin:
attribute {
name = "gsi1_pk"
type = "S"
}
attribute {
name = "gsi1_sk"
type = "S"
}
global_secondary_index {
name = "gsi1"
hash_key = "gsi1_pk"
range_key = "gsi1_sk"
projection_type = "ALL"
}
Bu değişikliği şu komutla uygulayın:
terraform apply -auto-approve
Sonra, bir öğrenciyi kaydetme şeklimizde küçük bir değişiklik yapmamız gerekiyor:
export const saveStudent = async ({
firstName,
lastName,
email,
}: {
firstName: string;
lastName: string;
email: string;
}): Promise<string> => {
const _id = uuidv4();
const _email = email.toLocaleLowerCase();
const xp = 0;
await client.putItem({
TableName: TABLE_NAME,
Item: {
pk: valueToAttributeValue(addPrefix(_id, STUDENT_PREFIX)),
sk: valueToAttributeValue(addPrefix(_id, STUDENT_PREFIX)),
gsi1_pk: valueToAttributeValue(_email),
gsi1_sk: valueToAttributeValue(addPrefix(_id, STUDENT_PREFIX)),
firstName: valueToAttributeValue(firstName),
lastName: valueToAttributeValue(lastName),
xp: valueToAttributeValue(xp),
entityType: valueToAttributeValue(entityType),
},
});
return _id;
};
Artık e-postayı açıkça saklamadığımıza, bunun yerine GSI PK değeri olarak kullandığımıza dikkat edin.
DynamoDB öğrenci verisini dönüştürme şeklimizde küçük bir ayar yapmamız gerekiyor:
export const dynamoRecordToStudent = (record: any) => {
const { pk, gsi1_pk, ...data } = record;
return omit(["sk", "gsi1_sk"], {
...attributeMapToValues(data),
id: removePrefix(attributeValueToValue<string>(pk), STUDENT_PREFIX),
email: attributeValueToValue<string>(gsi1_pk),
});
};
Son olarak, yeni oluşturduğumuz gsi1 GSI'ını kullanarak e-posta adresine göre bir öğrenci kaydı sorgulayabiliriz:
export const getStudentByEmail = (email: string) =>
client
.query({
TableName: TABLE_NAME,
IndexName: "gsi1",
KeyConditionExpression: "#gsi1_pk = :gsi1_pk",
ExpressionAttributeNames: {
"#gsi1_pk": "gsi1_pk",
},
ExpressionAttributeValues: {
":gsi1_pk": {
S: email.toLocaleLowerCase(),
},
},
})
.then((res) => head(pathOr([], ["Items"], res).map(dynamoRecordToStudent)));
Bir öğrenciyi güncelleme
Bir öğrenciyi güncellemek için update metodunu kullanmalı ve güncellemek istediğimiz öğeyi benzersiz şekilde tanımlamak adına hem bölüm hem de sıralama anahtarını sağlamalıyız.
export const updateStudent = async ({
id,
firstName,
lastName,
email,
}: {
id: string;
firstName?: string;
lastName?: string;
email?: string;
}) => {
const updateExpressionParts = [];
const ExpressionAttributeValues: Record<string, any> = {};
if (firstName !== undefined) {
updateExpressionParts.push("#firstName = :firstName");
ExpressionAttributeValues[":firstName"] = valueToAttributeValue(firstName);
}
if (lastName !== undefined) {
updateExpressionParts.push("#lastName = :lastName");
ExpressionAttributeValues[":lastName"] = valueToAttributeValue(lastName);
}
if (email !== undefined) {
updateExpressionParts.push("#gsi1_pk = :gsi1_pk");
ExpressionAttributeValues[":gsi1_pk"] = valueToAttributeValue(email);
}
const UpdateExpression = `SET ${updateExpressionParts.join(", ")}`;
const ExpressionAttributeNames = {
...(firstName && { "#firstName": "firstName" }),
...(lastName && { "#lastName": "lastName" }),
...(email && { "#gsi1_pk": "gsi1_pk" }),
};
await client.updateItem({
TableName: TABLE_NAME,
Key: {
pk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
sk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
},
UpdateExpression,
ExpressionAttributeNames,
ExpressionAttributeValues,
});
};
Veri silme
Öncelikle, DynamoDB'de bir tabloyu boşaltmanın (truncate) yerel olarak desteklenmediğini; bunun yalnızca tüm tabloyu silip yeniden oluşturarak mümkün olduğunu belirtelim (yeni bir GSI eklemek için daha önce yapmak zorunda kaldığımız gibi). client.ts'e bir boşaltma (truncate) yöntemi ekleyeceğim; ancak bunun yalnızca test amaçlı olduğunu ve üretimde kullanılmaması gerektiğini vurgulamak istiyorum. Nedeni şu ki neyin silineceğini bilmek için tüm tabloyu taramamız gerekiyor ve DynamoDB'deki her işlem maliyete yol açacaktır; dolayısıyla bir milyon öğeli bir tablonuz varsa, o tabloyu kaldırıp yeniden başlatmanız daha ucuz olacaktır (üretim verisini kaybetmemek için bir tür veri taşıma süreciyle). İşte truncate işlevimiz:
type AttributeMap = Record<string, AttributeValue>;
const getItemKeyAndValue = (item: AttributeMap, key?: string) =>
key ? { [`${key}`]: item[`${key}`] } : {};
export const truncateTable = async (
client: DynamoDB,
TableName: string,
hash: string,
range?: string
): Promise<void> => {
const { Items } = await client.scan({ TableName });
if (!Items) {
return;
}
const keys = Items.map((item: AttributeMap) => ({
...getItemKeyAndValue(item, hash),
...getItemKeyAndValue(item, range),
}));
if (!keys.length) {
return;
}
await Promise.all(keys?.map((Key) => client.deleteItem({ TableName, Key })));
};
demo-table'ı boşaltmak için:
await truncateTable(dynamoClient, TABLE_NAME, "pk", "sk");
Belirli bir öğrenciyi silmek için aslında SDK'daki deleteItem metodunu kullanmak istemeyiz. NoSQL veritabanlarında başvuru bütünlüğü kavramı yoktur; eğer veritabanımızda artık var olmayan bir öğrenciye atıfta bulunan başka öğeler varsa bu sorun olur ve DynamoDB, ilişkisel bir veritabanının yaptığı gibi yabancı anahtar referanslarını güvence altına alan bir güvenlik ağı sunmadan (ve ardından o silme işlemi için hata fırlatmadan) bize söylediğimiz herhangi bir öğeyi memnuniyetle silecektir.
Güvenli tarafta olmak için yumuşak silme (soft delete) uygulayacağız ve iki okuma fonksiyonumuzda küçük bir değişiklik yapacağız.
export const deleteStudent = async (id: string) => {
await client.updateItem({
TableName: TABLE_NAME,
Key: {
pk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
sk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
},
UpdateExpression: "SET #deleted = :deleted",
ExpressionAttributeNames: {
"#deleted": "deleted",
},
ExpressionAttributeValues: {
":deleted": valueToAttributeValue(true),
},
});
};
getStudentByEmail için yaptığımız sorgu artık silinmiş kayıtları filtrelemelidir. Bu “filtrelemenin” veritabanında değil istemci tarafında gerçekleştiğini ve bunun, silinmiş kayıtları almak için yine de aynı maliyeti doğuracağını unutmamak önemlidir.
{
TableName: TABLE_NAME,
IndexName: "gsi1",
KeyConditionExpression: "#gsi1_pk = :gsi1_pk",
ExpressionAttributeNames: {
"#gsi1_pk": "gsi1_pk",
},
ExpressionAttributeValues: {
":gsi1_pk": {
S: email.toLocaleLowerCase(),
},
":notDeleted": {
BOOL: false,
},
},
FilterExpression:
"attribute_not_exists(deleted) OR deleted = :notDeleted",
}
getStudentById fonksiyonu getItem kullanır; bu nedenle bir filtre ifadesi uygulama seçeneğimiz yoktur; bunun yerine mantığı açıkça yazacağız:
export const getStudentById = (id: string): Promise<Student | null> =>
client
.getItem({
TableName: TABLE_NAME,
Key: {
pk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
sk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
},
})
.then(({ Item }) => {
if (!Item) {
return null;
}
const _item = dynamoRecordToStudent(Item);
return _item.deleted ? null : _item;
});
ACID Uyumluluğuyla Atomik Güncellemeler
DataCamp, her öğrenci için XP verisi toplar; bu da motivasyon sağlar, başarı duygusu yaratır, genel ilerlemeyi takip etmeyi kolaylaştırır ve öğrencilerin kendilerini akranlarıyla kıyaslamalarına imkan tanır. İlişkisel bir veritabanında veriyi işlemek ve birleştirmek için çeşitli araçlara sahibiz; ancak bu NoSQL veritabanları için geçerli değildir. MongoDB gibi bazı NoSQL veritabanları bir toplulaştırma (aggregation) çerçevesi sunsa da, veritabanı büyük ölçeklere ulaştığında bu araçlar genellikle yetersiz kalır ve NoSQL seçme nedeni sıklıkla büyük veri ve trafik hacimlerini destekleme ihtiyacıdır.
DynamoDB'de atomik güncellemeler, bir öğenin tek bir özniteliği üzerinde belirli güncelleme işlemlerini, atomiklik, tutarlılık, yalıtım ve dayanıklılık (ACID özellikleri) sağlayacak şekilde gerçekleştirme yeteneğine karşılık gelir. Atomik güncellemeler, eşzamanlı güncellemeler olsa bile işlemin başarısını garanti eden şekilde belirli bir öznitelik değerini değiştiren işlemlerdir.
Bu tekniği kullanarak, bir kullanıcı bir öğrenme hedefini tamamladığında kolayca XP ekleyebiliriz.
export const updateStudentXp = async ({
id,
xp,
}: {
id: string;
xp: number;
}) => {
await client.updateItem({
TableName: TABLE_NAME,
Key: {
pk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
sk: valueToAttributeValue(addPrefix(id, STUDENT_PREFIX)),
},
UpdateExpression: "set xp = xp + :inc",
ExpressionAttributeValues: {
":inc": valueToAttributeValue(xp),
},
});
};
Bu kod tanıdık geldiyse, bunun nedeni deleteStudent işlevi için bu deseni zaten kullanmış olmamızdır!
Sonuç
Bu eğitimde, AWS tarafından sunulan, sunucusuz ve yüksek düzeyde ölçeklenebilir bir veritabanı olan Amazon DynamoDB'nin temellerini inceledik. DynamoDB'nin kesintisiz ölçeklenebilirlik, yüksek erişilebilirlik ve esnek veri modelleme gibi temel özellikleri, onu modern uygulamalar için mükemmel bir seçenek haline getirir.
Node.js kullanarak tablo oluşturma ve CRUD işlemleri gibi temel konuları ele aldık ve veri tutarlılığını korumak için atomik güncellemelerin önemini tartıştık. Eğitim boyunca bir veri modeli geliştirdik ve DynamoDB ile etkileşim kurmak için işlevler uyguladık.
DynamoDB yolculuğunuza devam ederken, tek tablo tasarımı, performans optimizasyonu ve gerçek zamanlı veri işleme için DynamoDB Streams gibi ileri düzey konulara dalmayı düşünün. DynamoDB'nin çok yönlülüğü ve ölçeklenebilirliği, AWS ekosistemi içinde yüksek performanslı, sunucusuz uygulamalar oluşturmanızı sağlar.
Bu eğitimdeki tam kaynak kodunu Github'da bulabilirsiniz. İyi kodlamalar!
Ek Öğrenme Materyalleri
- DataCamp eğitimi: DynamoDB ile tek tablo tasarımı
- DataCamp kursu: NoSQL kavramları
- AWS re:Invent: DynamoDB için İleri Düzey Tasarım Kalıpları
- Rick Houlihan: DynamoDB Tek Tablo Tasarımının Temelleri
- Alex DeBrie: DynamoDB kitabı
Öğrenmeye ve veriye tutkuyla bağlı, Tam Yığın Yazılım Mühendisi ve Çözüm Mimarıyım!

