Başlangıç6 dakikalık okuma

DynamoDB JSON ve Marshalling

DynamoDB API'sinden ilk kez ham veri okuduğunuzda, koyduğunuz JSON gibi görünmez. {"status": "open", "priority": 3} gibi düz bir nesne, {"status": {"S": "open"}, "priority": {"N": "3"}} olarak geri gelir. Her değer, türünü adlandıran tek anahtarlı bir nesneye sarılır. O sarma DynamoDB JSON'dur ve ona ve ondan dönüştürmeye marshalling denir.

Bu gürültü değildir — DynamoDB'nin türleri hat üzerinde belirsizlikten uzak tutmasının yoludur. Ama düz JSON bekleyen herkesin ayağına dolanır ve onu elle yazmak hataya açıktır.

DynamoDB JSON nedir?

DynamoDB JSON, DynamoDB'nin kullandığı tür etiketli hat formatıdır; burada her değer, türünü adlandıran tek anahtarlı bir nesneye sarılır — bir string için {"S": "open"}, bir sayı için {"N": "3"}. Düz JSON'u ona (ve geri) dönüştürmeye marshalling denir. Türleri belirsizlikten uzak tutar, çünkü düz JSON set'leri ya da binary'i ifade edemez ve DynamoDB sayıları hat üzerinde string olarak gittiği için etiketsiz bir 3 belirsiz olurdu.

  • DynamoDB JSON her değeri türüyle etiketler — bir string için {"S": "..."}, bir sayı için {"N": "..."} vb.
  • Marshalling = düz JSON → DynamoDB JSON. Unmarshalling = tersi.
  • Sayılar hat üzerinde string'dir{"N": "3"}, {"N": 3} değil — kesinliği korumak için.
  • Tür etiketleri, zaten modellediğiniz veri türü sistemidir — S, N, B, BOOL, NULL, L, M, SS, NS, BS.
  • Onu elle yazmayın. SDK'nın document client'ı (ya da bir dönüştürücü) senin için marshal eder; bunu yalnızca hata ayıklarken ya da ifadeler kurarken elle yapın.

Sorun: düz JSON yeterli değil

JSON'un tam olarak üç skaler türü vardır — string, sayı, boolean — artı null, diziler ve nesneler. DynamoDB'nin daha fazlası vardır: binary ve JSON'un hiç ifade edemediği üç set türü (string set, number set, binary set). Ve DynamoDB sayıları hat üzerinde string olarak gittiği için, etiketsiz bir 3 belirsiz olurdu — ayrıca JSON bir list'i bir set'ten ayırt edemez.

Bu yüzden DynamoDB JSON'unuzu olduğu gibi depolayamaz — her değerin tam türünü açıkça belirtmesi gerekir. Tür tanımlayıcısı, bunu her istek ve yanıtta kayıpsız biçimde yapmasının yoludur.

Kodlama nasıl çalışır

Her attribute değeri, anahtarı bir tür tanımlayıcısı olan tek anahtarlı bir nesne olur:

TanımlayıcıTürÖrnek
SString{"S": "open"}
NNumber (as a string){"N": "3"}
BBinary{"B": "dGV4dA=="}
BOOLBoolean{"BOOL": true}
NULLNull{"NULL": true}
LList{"L": [{"S": "a"}, {"N": "1"}]}
MMap{"M": {"k": {"S": "v"}}}
SS / NS / BSString / Sayı / Binary set{"SS": ["a", "b"]}

List'ler ve map'ler aynı tanımlayıcıları en aşağıya kadar iç içe geçirir, bu yüzden derinlemesine yapılandırılmış bir item derinlemesine sarılmış hâle gelir. Sayılar, hat üzerinde bilinçli olarak string olarak gider — bu, bir JSON sayısının (IEEE-754 bir double, ~15–17 anlamlı basamak) sessizce yuvarlayacağı tam 38 basamak sayısal kesinliği DynamoDB'nin korumasını sağlar. Bunlar, modellediğiniz aynı veri türleridir; DynamoDB JSON sadece onların açık hat üzeri biçimidir, AWS düşük seviyeli API referansında tanımlanmıştır.

İşlenmiş örnek: bir denetim günlüğü girdisi

Uygulamanızda yazacağınız düz JSON:

{
  "actor": "u-204",
  "action": "ticket.close",
  "ticketId": 8842,
  "tags": ["billing", "urgent"],
  "redacted": false
}

API için DynamoDB JSON'a marshal edilmiş:

{
  "actor": {"S": "u-204"},
  "action": {"S": "ticket.close"},
  "ticketId": {"N": "8842"},
  "tags": {"SS": ["billing", "urgent"]},
  "redacted": {"BOOL": false}
}

Bu item'ın ardındaki seçimlere dikkat edin: ticketId, string değerli bir N oldu; tags'in bir list değil bir string set (SS) olması, elle yapılmış bir modelleme seçimidir — düz JSON beslenen genel bir dönüştürücü L yayar, çünkü bir JSON dizisi sıralıdır ve tekrar edebilir, oysa SS yinelemeleri kaldırır ve sırasızdır. tags'in SS mi yoksa L mi olması gerektiği, dönüştürücünün senin için yapamayacağı bir modelleme kararıdır, ki bu tam olarak kodlamayı anlamanın neden önemli olduğudur.

DynoTable'da dönüştürme

Bunu elle okumanız ya da yazmanız nadiren gerekir. Düz JSON'u DynamoDB JSON dönüştürücüsüne yapıştırarak marshal edin (ve geri) ve bir istek kurarken, DynamoDB expression builder ifadeyle birlikte doğru marshal edilmiş attribute-value haritasını yayar. Uygulamanın kendisinde DynoTable, item'ları düz, okunabilir değerler olarak gösterir ve yazma sırasında senin için marshal eder.

DynoTable bir item'ı düz değerler olarak gösterirken, ham DynamoDB JSON da erişilebilir.
DynoTable bir item'ı düz değerler olarak gösterirken, ham DynamoDB JSON da erişilebilir.

Tuzaklar ve sonraki adımlar

  • DynamoDB JSON'da sayılar string'dir{"N": "3"}. Tırnak önemlidir; çıplak bir sayı yaymayın.
  • Set'lere karşı list'ler bir modelleme kararıdır ki kodlama onu görünür kılar — bilinçli seçin (bkz. veri türleri).
  • Uygulama kodunda elle marshal etmek yerine SDK document client'ını tercih edin; elle DynamoDB JSON'u hata ayıklama ve ifadeler için ayırın.
  • Boş string'ler anahtar olmayan attribute'lar için izinlidir (2020'den beri) ama tablo ve dizin anahtarları için hâlâ reddedilir ve tarihsel olarak araçların ayağına dolanmıştır — uç durumları doğrulayın.

Tür etiketlerini gözle çözmek yerine item'lara düz değerler olarak göz atmak mı istiyorsunuz? DynoTable'ı indirin ve verilerinizle doğrudan çalışın.

Düşük seviyeli client'a karşı document client

AWS SDK iki katman sunar:

KatmanGirdi biçimiKim marshal eder
@aws-sdk/client-dynamodb (düşük seviyeli)DynamoDB JSON AttributeValue haritalarıKodunuz ya da bir yardımcı
@aws-sdk/lib-dynamodb (document)Düz JS nesneleriGönderme/almada SDK

Uygulama kodu, PutItem/GetItem için varsayılan olarak document client'ı kullanmalıdır. Elle update expression yazdığınızda ya da bir kütüphane türlenmiş attribute değerleri beklediğinde düşük seviyeli haritalara başvurun.

İfade attribute değerleri de marshal edilir

ConditionExpression, UpdateExpression ve FilterExpression yer tutucuları (:val, :inc), ExpressionAttributeValues içindeki marshal edilmiş değerlere eşlenir:

":status": {"S": "open"}
":count": {"N": "1"}

Bir uyuşmazlık — düşük seviyeli client'ta S sarmalayıcısı olmadan "open" göndermek — ValidationException döndürür. İfade oluşturucu, haritayı ifade string'inin yanında yayar; böylece yer tutucular ve türler hizalı kalır.

Ayrılmış kelimelerle çakışan attribute adları ise bunun yerine ExpressionAttributeNames (#st) kullanır; denetleyici araç, alias haritasını yapıştırmaya hazır biçimde çıkarır.

Testlerde unmarshal sürprizleri

Marshalling'den kaynaklanan yaygın test hataları:

  • Boş set'ler — DynamoDB boş SS/NS/BS değerlerini reddeder; attribute'u bunun yerine hiç göndermeyin.
  • N içinde float'lar — hat üzerinde "3.14" değerini bir JSON sayısı olarak değil, string olarak gönderin.
  • Node'da binary — document client'ta Uint8Array; ham JSON'da base64.
  • Tanımsız attribute'lar — document client undefined değerleri ayıklar; düşük seviyeli client geçersiz payload gönderebilir.

Bir Lambda ham API yanıtlarını loglarken, fixture'larla karşılaştırmadan önce bir item'ı DynamoDB JSON dönüştürücüsüne yapıştırıp okunabilir düz JSON'a çevirin.

Etiketlemenin boyut etkisi

Her tür sarmalayıcısı bayt ekler. Alan alan marshal edilmiş düz bir JSON nesnesi, attribute adlarına bağlı olarak hat üzerinde kabaca %30–40 büyür — bu şişme item boyutunu ve RCU/WCU yuvarlamasını besler. Kısa attribute adlarına sahip büyük map'ler ek yükü amorti eder; minicik boolean bayrakları ise yine de kendi anahtar adlarının ve {"BOOL":true} değerinin bedelini öder.

Marshal edilmiş item'ları toplu yüklemeden önce toplam baytı item boyutu hesaplayıcısında kontrol edin; böylece bir batch write beklenmedik biçimde 16 MB istek sınırını aşmasın.

DynoTable'ın iki görünümü

Item editörü, marshalling'i günden güne görünmez tutar — düz değerleri düzenlersiniz ve commit'ler gönderim sırasında marshal edilir. CloudWatch loglarından kopyalanmış bir production item'ında hata ayıklarken, tam etiketleri görmek için DynamoDB JSON görünümüne geçin, sonra düzenleme için Düz JSON'a geri dönün. Dışa aktarma eylemleri, ticket'lar ve test senaryoları için her iki temsili de kopyalar.

Güncellendi